nitrostack 1.0.0 → 1.0.1

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 (115) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/templates/typescript-auth/.env.example +23 -0
  4. package/templates/typescript-auth/src/app.module.ts +103 -0
  5. package/templates/typescript-auth/src/db/database.ts +163 -0
  6. package/templates/typescript-auth/src/db/seed.ts +374 -0
  7. package/templates/typescript-auth/src/db/setup.ts +87 -0
  8. package/templates/typescript-auth/src/events/analytics.service.ts +52 -0
  9. package/templates/typescript-auth/src/events/notification.service.ts +40 -0
  10. package/templates/typescript-auth/src/filters/global-exception.filter.ts +28 -0
  11. package/templates/typescript-auth/src/guards/README.md +75 -0
  12. package/templates/typescript-auth/src/guards/jwt.guard.ts +105 -0
  13. package/templates/typescript-auth/src/health/database.health.ts +41 -0
  14. package/templates/typescript-auth/src/index.ts +26 -0
  15. package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +24 -0
  16. package/templates/typescript-auth/src/middleware/logging.middleware.ts +42 -0
  17. package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +16 -0
  18. package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +114 -0
  19. package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +40 -0
  20. package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +241 -0
  21. package/templates/typescript-auth/src/modules/auth/auth.module.ts +16 -0
  22. package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +147 -0
  23. package/templates/typescript-auth/src/modules/auth/auth.resources.ts +84 -0
  24. package/templates/typescript-auth/src/modules/auth/auth.tools.ts +139 -0
  25. package/templates/typescript-auth/src/modules/cart/cart.module.ts +16 -0
  26. package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +95 -0
  27. package/templates/typescript-auth/src/modules/cart/cart.resources.ts +44 -0
  28. package/templates/typescript-auth/src/modules/cart/cart.tools.ts +281 -0
  29. package/templates/typescript-auth/src/modules/orders/orders.module.ts +16 -0
  30. package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +88 -0
  31. package/templates/typescript-auth/src/modules/orders/orders.resources.ts +48 -0
  32. package/templates/typescript-auth/src/modules/orders/orders.tools.ts +281 -0
  33. package/templates/typescript-auth/src/modules/products/products.module.ts +16 -0
  34. package/templates/typescript-auth/src/modules/products/products.prompts.ts +146 -0
  35. package/templates/typescript-auth/src/modules/products/products.resources.ts +98 -0
  36. package/templates/typescript-auth/src/modules/products/products.tools.ts +266 -0
  37. package/templates/typescript-auth/src/pipes/validation.pipe.ts +42 -0
  38. package/templates/typescript-auth/src/services/database.service.ts +90 -0
  39. package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +122 -0
  40. package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +116 -0
  41. package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +105 -0
  42. package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +139 -0
  43. package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +153 -0
  44. package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +86 -0
  45. package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +116 -0
  46. package/templates/typescript-auth/src/widgets/app/categories/page.tsx +134 -0
  47. package/templates/typescript-auth/src/widgets/app/layout.tsx +21 -0
  48. package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +129 -0
  49. package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +206 -0
  50. package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +225 -0
  51. package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +218 -0
  52. package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +121 -0
  53. package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +173 -0
  54. package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +187 -0
  55. package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +165 -0
  56. package/templates/typescript-auth/src/widgets/next.config.js +38 -0
  57. package/templates/typescript-auth/src/widgets/package.json +18 -0
  58. package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +169 -0
  59. package/templates/typescript-auth/src/widgets/tsconfig.json +28 -0
  60. package/templates/typescript-auth/src/widgets/types/tool-data.ts +141 -0
  61. package/templates/typescript-auth/src/widgets/widget-manifest.json +464 -0
  62. package/templates/typescript-auth/tsconfig.json +27 -0
  63. package/templates/typescript-auth-api-key/.env +15 -0
  64. package/templates/typescript-auth-api-key/.env.example +4 -0
  65. package/templates/typescript-auth-api-key/src/app.module.ts +38 -0
  66. package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +47 -0
  67. package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +157 -0
  68. package/templates/typescript-auth-api-key/src/health/system.health.ts +55 -0
  69. package/templates/typescript-auth-api-key/src/index.ts +47 -0
  70. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +12 -0
  71. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +73 -0
  72. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +60 -0
  73. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +71 -0
  74. package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +18 -0
  75. package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +155 -0
  76. package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +123 -0
  77. package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +133 -0
  78. package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +134 -0
  79. package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +14 -0
  80. package/templates/typescript-auth-api-key/src/widgets/next.config.js +37 -0
  81. package/templates/typescript-auth-api-key/src/widgets/package.json +24 -0
  82. package/templates/typescript-auth-api-key/src/widgets/tsconfig.json +28 -0
  83. package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +48 -0
  84. package/templates/typescript-auth-api-key/tsconfig.json +23 -0
  85. package/templates/typescript-oauth/.env.example +91 -0
  86. package/templates/typescript-oauth/src/app.module.ts +89 -0
  87. package/templates/typescript-oauth/src/guards/oauth.guard.ts +127 -0
  88. package/templates/typescript-oauth/src/index.ts +74 -0
  89. package/templates/typescript-oauth/src/modules/demo/demo.module.ts +16 -0
  90. package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +190 -0
  91. package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +133 -0
  92. package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +134 -0
  93. package/templates/typescript-oauth/src/widgets/app/layout.tsx +14 -0
  94. package/templates/typescript-oauth/src/widgets/next.config.js +37 -0
  95. package/templates/typescript-oauth/src/widgets/package.json +24 -0
  96. package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
  97. package/templates/typescript-oauth/src/widgets/widget-manifest.json +48 -0
  98. package/templates/typescript-oauth/tsconfig.json +23 -0
  99. package/templates/typescript-starter/.env.example +4 -0
  100. package/templates/typescript-starter/src/app.module.ts +34 -0
  101. package/templates/typescript-starter/src/health/system.health.ts +55 -0
  102. package/templates/typescript-starter/src/index.ts +27 -0
  103. package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
  104. package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
  105. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +60 -0
  106. package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +71 -0
  107. package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +133 -0
  108. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +134 -0
  109. package/templates/typescript-starter/src/widgets/app/layout.tsx +14 -0
  110. package/templates/typescript-starter/src/widgets/next.config.js +37 -0
  111. package/templates/typescript-starter/src/widgets/package.json +24 -0
  112. package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
  113. package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
  114. package/templates/typescript-starter/tsconfig.json +23 -0
  115. package/LICENSE_URLS_UPDATE_COMPLETE.md +0 -388
@@ -0,0 +1,225 @@
1
+ 'use client';
2
+
3
+ import { withToolData } from 'nitrostack/widgets';
4
+ import * as styles from '../../styles/ecommerce';
5
+
6
+ interface OrderItem {
7
+ product_id: string;
8
+ name: string;
9
+ quantity: number;
10
+ price: number;
11
+ image_url?: string;
12
+ }
13
+
14
+ interface OrderDetailsData {
15
+ order: {
16
+ id: string;
17
+ total: number;
18
+ status: string;
19
+ payment_method: string;
20
+ created_at: string;
21
+ full_name?: string;
22
+ street?: string;
23
+ city?: string;
24
+ state?: string;
25
+ zip_code?: string;
26
+ };
27
+ items: OrderItem[];
28
+ }
29
+
30
+ function OrderDetailsWidget({ data }: { data: OrderDetailsData }) {
31
+ const { order, items } = data;
32
+
33
+ return (
34
+ <div style={styles.containerStyle}>
35
+ <div style={{
36
+ ...styles.cardStyle,
37
+ maxWidth: '700px',
38
+ margin: '0 auto',
39
+ }}>
40
+ <div style={{
41
+ display: 'flex',
42
+ justifyContent: 'space-between',
43
+ alignItems: 'flex-start',
44
+ marginBottom: styles.spacing.xl,
45
+ paddingBottom: styles.spacing.lg,
46
+ borderBottom: `2px solid ${styles.colors.gray[200]}`,
47
+ }}>
48
+ <div>
49
+ <h2 style={{
50
+ fontSize: styles.typography.fontSize['2xl'],
51
+ fontWeight: styles.typography.fontWeight.bold,
52
+ color: styles.colors.gray[900],
53
+ marginBottom: styles.spacing.xs,
54
+ }}>
55
+ Order #{order.id.substring(0, 8).toUpperCase()}
56
+ </h2>
57
+ <div style={styles.metaTextStyle}>
58
+ Placed on {new Date(order.created_at).toLocaleDateString('en-US', {
59
+ year: 'numeric',
60
+ month: 'long',
61
+ day: 'numeric',
62
+ hour: '2-digit',
63
+ minute: '2-digit',
64
+ })}
65
+ </div>
66
+ </div>
67
+
68
+ <div style={{
69
+ ...styles.badgeStyle,
70
+ background: order.status === 'pending'
71
+ ? styles.colors.warning
72
+ : order.status === 'delivered'
73
+ ? styles.colors.success
74
+ : styles.colors.primary,
75
+ color: styles.colors.white,
76
+ padding: `${styles.spacing.sm} ${styles.spacing.lg}`,
77
+ }}>
78
+ {order.status}
79
+ </div>
80
+ </div>
81
+
82
+ <div style={{ marginBottom: styles.spacing.xl }}>
83
+ <h3 style={{
84
+ fontSize: styles.typography.fontSize.lg,
85
+ fontWeight: styles.typography.fontWeight.semibold,
86
+ color: styles.colors.gray[900],
87
+ marginBottom: styles.spacing.md,
88
+ }}>
89
+ Order Items
90
+ </h3>
91
+
92
+ <div style={{
93
+ display: 'flex',
94
+ flexDirection: 'column',
95
+ gap: styles.spacing.md,
96
+ }}>
97
+ {items && items.map((item, index) => (
98
+ <div
99
+ key={item.product_id || index}
100
+ style={{
101
+ display: 'flex',
102
+ gap: styles.spacing.md,
103
+ padding: styles.spacing.md,
104
+ background: styles.colors.gray[50],
105
+ borderRadius: styles.borderRadius.md,
106
+ }}
107
+ >
108
+ {item.image_url && (
109
+ <div style={{
110
+ width: '80px',
111
+ height: '80px',
112
+ flexShrink: 0,
113
+ borderRadius: styles.borderRadius.md,
114
+ overflow: 'hidden',
115
+ background: styles.colors.white,
116
+ }}>
117
+ <img
118
+ src={item.image_url}
119
+ alt={item.name}
120
+ style={{
121
+ width: '100%',
122
+ height: '100%',
123
+ objectFit: 'cover',
124
+ }}
125
+ />
126
+ </div>
127
+ )}
128
+
129
+ <div style={{ flex: 1 }}>
130
+ <div style={{
131
+ fontSize: styles.typography.fontSize.base,
132
+ fontWeight: styles.typography.fontWeight.semibold,
133
+ color: styles.colors.gray[900],
134
+ marginBottom: styles.spacing.xs,
135
+ }}>
136
+ {item.name}
137
+ </div>
138
+ <div style={styles.metaTextStyle}>
139
+ Quantity: {item.quantity} × ${item.price.toFixed(2)}
140
+ </div>
141
+ </div>
142
+
143
+ <div style={{
144
+ fontSize: styles.typography.fontSize.xl,
145
+ fontWeight: styles.typography.fontWeight.bold,
146
+ color: styles.colors.primary,
147
+ }}>
148
+ ${(item.price * item.quantity).toFixed(2)}
149
+ </div>
150
+ </div>
151
+ ))}
152
+ </div>
153
+ </div>
154
+
155
+ <div style={{
156
+ ...styles.cardStyle,
157
+ background: `linear-gradient(135deg, ${styles.colors.gray[900]} 0%, ${styles.colors.gray[800]} 100%)`,
158
+ border: `2px solid ${styles.colors.primary}`,
159
+ marginBottom: styles.spacing.xl,
160
+ }}>
161
+ <div style={{
162
+ display: 'flex',
163
+ justifyContent: 'space-between',
164
+ alignItems: 'center',
165
+ }}>
166
+ <div style={{
167
+ fontSize: styles.typography.fontSize.lg,
168
+ color: styles.colors.gray[300],
169
+ fontWeight: styles.typography.fontWeight.semibold,
170
+ }}>
171
+ Order Total
172
+ </div>
173
+ <div style={{
174
+ fontSize: styles.typography.fontSize['3xl'],
175
+ fontWeight: styles.typography.fontWeight.bold,
176
+ color: styles.colors.primary,
177
+ }}>
178
+ ${order.total.toFixed(2)}
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ {(order.full_name || order.street) && (
184
+ <div>
185
+ <h3 style={{
186
+ fontSize: styles.typography.fontSize.lg,
187
+ fontWeight: styles.typography.fontWeight.semibold,
188
+ color: styles.colors.gray[900],
189
+ marginBottom: styles.spacing.md,
190
+ }}>
191
+ Delivery Address
192
+ </h3>
193
+
194
+ <div style={{
195
+ background: styles.colors.gray[50],
196
+ borderRadius: styles.borderRadius.md,
197
+ padding: styles.spacing.lg,
198
+ }}>
199
+ <div style={{
200
+ fontSize: styles.typography.fontSize.base,
201
+ color: styles.colors.gray[800],
202
+ lineHeight: styles.typography.lineHeight.relaxed,
203
+ }}>
204
+ {order.full_name && (
205
+ <div style={{
206
+ fontWeight: styles.typography.fontWeight.semibold,
207
+ marginBottom: styles.spacing.xs,
208
+ }}>
209
+ {order.full_name}
210
+ </div>
211
+ )}
212
+ {order.street && <div>{order.street}</div>}
213
+ {(order.city || order.state || order.zip_code) && (
214
+ <div>{order.city}, {order.state} {order.zip_code}</div>
215
+ )}
216
+ </div>
217
+ </div>
218
+ </div>
219
+ )}
220
+ </div>
221
+ </div>
222
+ );
223
+ }
224
+
225
+ export default withToolData<OrderDetailsData>(OrderDetailsWidget);
@@ -0,0 +1,218 @@
1
+ 'use client';
2
+
3
+ import { withToolData } from 'nitrostack/widgets';
4
+ import { OrderHistoryData } from '../../types/tool-data';
5
+ import * as styles from '../../styles/ecommerce';
6
+
7
+ function OrderHistoryWidget({ data }: { data: OrderHistoryData }) {
8
+ const { orders, pagination } = data;
9
+
10
+ if (orders.length === 0) {
11
+ return (
12
+ <div style={styles.containerStyle}>
13
+ <div style={styles.emptyStateStyle}>
14
+ <div style={{ fontSize: '64px', marginBottom: styles.spacing.lg }}>
15
+ 📦
16
+ </div>
17
+ <h3 style={{
18
+ fontSize: styles.typography.fontSize.xl,
19
+ fontWeight: styles.typography.fontWeight.semibold,
20
+ color: styles.colors.gray[700],
21
+ marginBottom: styles.spacing.sm,
22
+ }}>
23
+ No orders yet
24
+ </h3>
25
+ <p style={styles.metaTextStyle}>
26
+ Your order history will appear here
27
+ </p>
28
+ </div>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ return (
34
+ <div style={styles.containerStyle}>
35
+ <div style={{
36
+ ...styles.titleStyle,
37
+ justifyContent: 'space-between',
38
+ }}>
39
+ <span>
40
+ 📦 Order History
41
+ </span>
42
+ <span style={{
43
+ ...styles.badgeStyle,
44
+ background: styles.colors.primary,
45
+ color: styles.colors.black,
46
+ }}>
47
+ {orders.length} orders
48
+ </span>
49
+ </div>
50
+
51
+ <div style={{
52
+ display: 'flex',
53
+ flexDirection: 'column',
54
+ gap: styles.spacing.lg,
55
+ }}>
56
+ {orders.map((order) => (
57
+ <div
58
+ key={order.id}
59
+ style={{
60
+ ...styles.cardStyle,
61
+ cursor: 'pointer',
62
+ }}
63
+ onMouseEnter={(e) => {
64
+ e.currentTarget.style.transform = 'translateY(-2px)';
65
+ e.currentTarget.style.boxShadow = styles.shadows.lg;
66
+ }}
67
+ onMouseLeave={(e) => {
68
+ e.currentTarget.style.transform = 'translateY(0)';
69
+ e.currentTarget.style.boxShadow = styles.shadows.md;
70
+ }}
71
+ >
72
+ <div style={{
73
+ display: 'flex',
74
+ justifyContent: 'space-between',
75
+ alignItems: 'flex-start',
76
+ marginBottom: styles.spacing.md,
77
+ }}>
78
+ <div>
79
+ <div style={{
80
+ fontSize: styles.typography.fontSize.lg,
81
+ fontWeight: styles.typography.fontWeight.semibold,
82
+ color: styles.colors.gray[900],
83
+ marginBottom: styles.spacing.xs,
84
+ }}>
85
+ Order #{order.id.substring(0, 8).toUpperCase()}
86
+ </div>
87
+ <div style={styles.metaTextStyle}>
88
+ {new Date(order.created_at).toLocaleDateString('en-US', {
89
+ year: 'numeric',
90
+ month: 'long',
91
+ day: 'numeric',
92
+ })}
93
+ </div>
94
+ </div>
95
+
96
+ <div style={{
97
+ ...styles.badgeStyle,
98
+ background: order.status === 'pending'
99
+ ? styles.colors.warning
100
+ : order.status === 'delivered'
101
+ ? styles.colors.success
102
+ : styles.colors.primary,
103
+ color: styles.colors.white,
104
+ }}>
105
+ {order.status}
106
+ </div>
107
+ </div>
108
+
109
+ {order.items && order.items.length > 0 && (
110
+ <div style={{
111
+ display: 'flex',
112
+ gap: styles.spacing.sm,
113
+ marginBottom: styles.spacing.md,
114
+ overflowX: 'auto',
115
+ }}>
116
+ {order.items.slice(0, 4).map((item) => (
117
+ item.image_url && (
118
+ <div
119
+ key={item.id}
120
+ style={{
121
+ width: '60px',
122
+ height: '60px',
123
+ flexShrink: 0,
124
+ borderRadius: styles.borderRadius.md,
125
+ overflow: 'hidden',
126
+ background: styles.colors.gray[100],
127
+ border: `2px solid ${styles.colors.white}`,
128
+ }}
129
+ >
130
+ <img
131
+ src={item.image_url}
132
+ alt={item.name}
133
+ style={{
134
+ width: '100%',
135
+ height: '100%',
136
+ objectFit: 'cover',
137
+ }}
138
+ />
139
+ </div>
140
+ )
141
+ ))}
142
+ {order.items.length > 4 && (
143
+ <div style={{
144
+ width: '60px',
145
+ height: '60px',
146
+ flexShrink: 0,
147
+ borderRadius: styles.borderRadius.md,
148
+ background: styles.colors.gray[200],
149
+ display: 'flex',
150
+ alignItems: 'center',
151
+ justifyContent: 'center',
152
+ fontSize: styles.typography.fontSize.sm,
153
+ fontWeight: styles.typography.fontWeight.semibold,
154
+ color: styles.colors.gray[600],
155
+ }}>
156
+ +{order.items.length - 4}
157
+ </div>
158
+ )}
159
+ </div>
160
+ )}
161
+
162
+ <div style={{
163
+ display: 'flex',
164
+ justifyContent: 'space-between',
165
+ alignItems: 'center',
166
+ paddingTop: styles.spacing.md,
167
+ borderTop: `1px solid ${styles.colors.gray[200]}`,
168
+ }}>
169
+ <div>
170
+ <div style={styles.metaTextStyle}>
171
+ {order.itemCount || order.items?.length || 0} {(order.itemCount || order.items?.length || 0) === 1 ? 'item' : 'items'}
172
+ </div>
173
+ </div>
174
+
175
+ <div style={{
176
+ fontSize: styles.typography.fontSize['2xl'],
177
+ fontWeight: styles.typography.fontWeight.bold,
178
+ color: styles.colors.primary,
179
+ }}>
180
+ ${order.total.toFixed(2)}
181
+ </div>
182
+ </div>
183
+
184
+ {order.full_name && (
185
+ <div style={{
186
+ marginTop: styles.spacing.md,
187
+ padding: styles.spacing.md,
188
+ background: styles.colors.gray[50],
189
+ borderRadius: styles.borderRadius.md,
190
+ fontSize: styles.typography.fontSize.sm,
191
+ color: styles.colors.gray[700],
192
+ }}>
193
+ 📍 Delivered to: {order.full_name}, {order.city}, {order.state}
194
+ </div>
195
+ )}
196
+ </div>
197
+ ))}
198
+ </div>
199
+
200
+ {pagination.totalPages > 1 && (
201
+ <div style={{
202
+ marginTop: styles.spacing.xl,
203
+ textAlign: 'center',
204
+ padding: styles.spacing.lg,
205
+ background: styles.colors.white,
206
+ borderRadius: styles.borderRadius.md,
207
+ boxShadow: styles.shadows.sm,
208
+ }}>
209
+ <div style={styles.metaTextStyle}>
210
+ Page {pagination.page} of {pagination.totalPages} • {pagination.total} total orders
211
+ </div>
212
+ </div>
213
+ )}
214
+ </div>
215
+ );
216
+ }
217
+
218
+ export default withToolData<OrderHistoryData>(OrderHistoryWidget);
@@ -0,0 +1,121 @@
1
+ 'use client';
2
+
3
+ import { withToolData } from 'nitrostack/widgets';
4
+ import { ProductCardData } from '../../types/tool-data';
5
+ import * as styles from '../../styles/ecommerce';
6
+
7
+ function ProductCardWidget({ data }: { data: ProductCardData }) {
8
+ const { product } = data;
9
+
10
+ return (
11
+ <div style={styles.containerStyle}>
12
+ <div style={{
13
+ ...styles.cardStyle,
14
+ maxWidth: '600px',
15
+ margin: '0 auto',
16
+ overflow: 'hidden',
17
+ padding: 0,
18
+ }}>
19
+ <div style={{
20
+ position: 'relative',
21
+ paddingTop: '60%',
22
+ background: styles.colors.gray[100],
23
+ }}>
24
+ <img
25
+ src={product.image_url}
26
+ alt={product.name}
27
+ style={{
28
+ position: 'absolute',
29
+ top: 0,
30
+ left: 0,
31
+ width: '100%',
32
+ height: '100%',
33
+ objectFit: 'cover',
34
+ }}
35
+ />
36
+ <div style={{
37
+ position: 'absolute',
38
+ top: styles.spacing.lg,
39
+ right: styles.spacing.lg,
40
+ ...styles.badgeStyle,
41
+ background: styles.colors.white,
42
+ boxShadow: styles.shadows.lg,
43
+ padding: `${styles.spacing.sm} ${styles.spacing.md}`,
44
+ }}>
45
+ {product.stock > 0 ? `${product.stock} in stock` : 'Out of stock'}
46
+ </div>
47
+ </div>
48
+
49
+ <div style={{ padding: styles.spacing.xl }}>
50
+ <div style={{
51
+ fontSize: styles.typography.fontSize.sm,
52
+ color: styles.colors.gray[500],
53
+ marginBottom: styles.spacing.sm,
54
+ textTransform: 'uppercase',
55
+ letterSpacing: '1px',
56
+ fontWeight: styles.typography.fontWeight.semibold,
57
+ }}>
58
+ {product.category}
59
+ </div>
60
+
61
+ <h1 style={{
62
+ fontSize: styles.typography.fontSize['3xl'],
63
+ fontWeight: styles.typography.fontWeight.bold,
64
+ color: styles.colors.gray[900],
65
+ marginBottom: styles.spacing.md,
66
+ lineHeight: styles.typography.lineHeight.tight,
67
+ }}>
68
+ {product.name}
69
+ </h1>
70
+
71
+ <p style={{
72
+ fontSize: styles.typography.fontSize.base,
73
+ color: styles.colors.gray[700],
74
+ lineHeight: styles.typography.lineHeight.relaxed,
75
+ marginBottom: styles.spacing.xl,
76
+ }}>
77
+ {product.description}
78
+ </p>
79
+
80
+ <div style={{
81
+ display: 'flex',
82
+ justifyContent: 'space-between',
83
+ alignItems: 'center',
84
+ paddingTop: styles.spacing.lg,
85
+ borderTop: `2px solid ${styles.colors.gray[200]}`,
86
+ }}>
87
+ <div>
88
+ <div style={{
89
+ fontSize: styles.typography.fontSize.sm,
90
+ color: styles.colors.gray[500],
91
+ marginBottom: styles.spacing.xs,
92
+ }}>
93
+ Price
94
+ </div>
95
+ <div style={{
96
+ fontSize: styles.typography.fontSize['3xl'],
97
+ fontWeight: styles.typography.fontWeight.bold,
98
+ color: styles.colors.primary,
99
+ }}>
100
+ ${product.price.toFixed(2)}
101
+ </div>
102
+ </div>
103
+
104
+ <div style={{
105
+ ...styles.buttonStyle,
106
+ padding: `${styles.spacing.lg} ${styles.spacing['2xl']}`,
107
+ fontSize: styles.typography.fontSize.base,
108
+ display: 'flex',
109
+ alignItems: 'center',
110
+ gap: styles.spacing.sm,
111
+ }}>
112
+ 🛒 Add to Cart
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ );
119
+ }
120
+
121
+ export default withToolData<ProductCardData>(ProductCardWidget);