@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.
- package/README.md +131 -0
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +185 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +365 -0
- package/dist/commands/generate-types.d.ts +8 -0
- package/dist/commands/generate-types.d.ts.map +1 -0
- package/dist/commands/generate-types.js +219 -0
- package/dist/commands/generate.d.ts +12 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +375 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +324 -0
- package/dist/commands/install.d.ts +10 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +80 -0
- package/dist/commands/start.d.ts +6 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +70 -0
- package/dist/commands/upgrade.d.ts +10 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +214 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/mcp-dev-wrapper.d.ts +15 -0
- package/dist/mcp-dev-wrapper.d.ts.map +1 -0
- package/dist/mcp-dev-wrapper.js +187 -0
- package/dist/ui/branding.d.ts +31 -0
- package/dist/ui/branding.d.ts.map +1 -0
- package/dist/ui/branding.js +136 -0
- package/package.json +69 -0
- package/templates/typescript-oauth/.env.example +27 -0
- package/templates/typescript-oauth/OAUTH_SETUP.md +592 -0
- package/templates/typescript-oauth/README.md +263 -0
- package/templates/typescript-oauth/package.json +29 -0
- package/templates/typescript-oauth/src/app.module.ts +92 -0
- package/templates/typescript-oauth/src/guards/oauth.guard.ts +126 -0
- package/templates/typescript-oauth/src/health/system.health.ts +55 -0
- package/templates/typescript-oauth/src/index.ts +63 -0
- package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
- package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
- package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +228 -0
- package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
- package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
- package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
- package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
- package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
- package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
- package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
- package/templates/typescript-oauth/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
- package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
- package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
- package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
- package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
- package/templates/typescript-oauth/src/widgets/next.config.js +45 -0
- package/templates/typescript-oauth/src/widgets/package-lock.json +4493 -0
- package/templates/typescript-oauth/src/widgets/package.json +24 -0
- package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-oauth/src/widgets/widget-manifest.json +395 -0
- package/templates/typescript-oauth/tsconfig.json +23 -0
- package/templates/typescript-pizzaz/README.md +252 -0
- package/templates/typescript-pizzaz/package.json +34 -0
- package/templates/typescript-pizzaz/src/app.module.ts +28 -0
- package/templates/typescript-pizzaz/src/index.ts +30 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
- package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
- package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
- package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
- package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
- package/templates/typescript-pizzaz/src/widgets/next.config.js +45 -0
- package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
- package/templates/typescript-pizzaz/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
- package/templates/typescript-pizzaz/tsconfig.json +30 -0
- package/templates/typescript-starter/README.md +320 -0
- package/templates/typescript-starter/package.json +25 -0
- package/templates/typescript-starter/src/app.module.ts +34 -0
- package/templates/typescript-starter/src/health/system.health.ts +55 -0
- package/templates/typescript-starter/src/index.ts +29 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +59 -0
- package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +166 -0
- package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +180 -0
- package/templates/typescript-starter/src/widgets/app/layout.tsx +18 -0
- package/templates/typescript-starter/src/widgets/next.config.js +45 -0
- package/templates/typescript-starter/src/widgets/package.json +24 -0
- package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
- package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
- 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
|
+
}
|