popsite-ui 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 (87) hide show
  1. package/App.jsx +95 -0
  2. package/README.md +92 -0
  3. package/components/layout/PortalHeader.jsx +18 -0
  4. package/components/layout/SystemSidebar.jsx +33 -0
  5. package/components/modules/AnalyticsDashboardModule.jsx +17 -0
  6. package/components/modules/ChatMessagingModule.jsx +17 -0
  7. package/components/modules/EcommerceStoreModule.jsx +17 -0
  8. package/components/modules/EventTicketBookingModule.jsx +17 -0
  9. package/components/modules/FlightBookingModule.jsx +17 -0
  10. package/components/modules/FoodOrderingModule.jsx +17 -0
  11. package/components/modules/HospitalAppointmentModule.jsx +17 -0
  12. package/components/modules/HotelBookingModule.jsx +17 -0
  13. package/components/modules/InvoiceBillingModule.jsx +17 -0
  14. package/components/modules/LibraryManagementModule.jsx +17 -0
  15. package/components/modules/ModuleContentDeck.jsx +44 -0
  16. package/components/modules/MovieBookingModule.jsx +17 -0
  17. package/components/modules/QuizExamModule.jsx +17 -0
  18. package/components/modules/StudentRegistrationModule.jsx +17 -0
  19. package/components/modules/SystemModuleRenderer.jsx +19 -0
  20. package/components/modules/SystemModuleTemplate.jsx +62 -0
  21. package/components/modules/SystemVisualWidget.jsx +123 -0
  22. package/components/modules/moduleContentMap.js +238 -0
  23. package/components/modules/moduleEnhancementsMap.js +439 -0
  24. package/components/modules/systemModuleMap.js +31 -0
  25. package/components/system/DynamicSystemForm.jsx +154 -0
  26. package/components/system/SystemHero.jsx +21 -0
  27. package/components/system/SystemSummaryCard.jsx +53 -0
  28. package/data/systems/analyticsDashboard.js +48 -0
  29. package/data/systems/chatMessaging.js +43 -0
  30. package/data/systems/ecommerceStore.js +50 -0
  31. package/data/systems/eventTicketBooking.js +50 -0
  32. package/data/systems/flightBooking.js +38 -0
  33. package/data/systems/foodOrdering.js +48 -0
  34. package/data/systems/hospitalAppointment.js +50 -0
  35. package/data/systems/hotelBooking.js +38 -0
  36. package/data/systems/index.js +31 -0
  37. package/data/systems/invoiceBilling.js +50 -0
  38. package/data/systems/libraryManagement.js +43 -0
  39. package/data/systems/movieBooking.js +48 -0
  40. package/data/systems/quizExam.js +38 -0
  41. package/data/systems/studentRegistration.js +43 -0
  42. package/dist/popsite-ui.es.js +4368 -0
  43. package/dist/popsite-ui.umd.js +60 -0
  44. package/dist/style.css +1 -0
  45. package/index.html +13 -0
  46. package/library/index.js +20 -0
  47. package/main.jsx +15 -0
  48. package/package.json +40 -0
  49. package/src/App.jsx +12 -0
  50. package/src/components/modules/AnalyticsDashboardModule.jsx +224 -0
  51. package/src/components/modules/ChatMessagingModule.jsx +294 -0
  52. package/src/components/modules/EcommerceStoreModule.jsx +405 -0
  53. package/src/components/modules/EventTicketBookingModule.jsx +253 -0
  54. package/src/components/modules/FlightBookingModule.jsx +399 -0
  55. package/src/components/modules/FoodOrderingModule.jsx +316 -0
  56. package/src/components/modules/HospitalAppointmentModule.jsx +267 -0
  57. package/src/components/modules/HotelBookingModule.jsx +317 -0
  58. package/src/components/modules/InvoiceBillingModule.jsx +302 -0
  59. package/src/components/modules/LandingPageModule.jsx +185 -0
  60. package/src/components/modules/LibraryManagementModule.jsx +189 -0
  61. package/src/components/modules/MovieBookingModule.jsx +337 -0
  62. package/src/components/modules/QuizExamModule.jsx +255 -0
  63. package/src/components/modules/StudentRegistrationModule.jsx +292 -0
  64. package/src/components/system/SystemHero.jsx +44 -0
  65. package/src/components/system/SystemSummaryCard.jsx +29 -0
  66. package/src/components/system/Toast.jsx +69 -0
  67. package/src/data/systems/analyticsDashboard.js +32 -0
  68. package/src/data/systems/chatMessaging.js +59 -0
  69. package/src/data/systems/ecommerceStore.js +84 -0
  70. package/src/data/systems/eventBooking.js +33 -0
  71. package/src/data/systems/flightBooking.js +59 -0
  72. package/src/data/systems/foodOrdering.js +48 -0
  73. package/src/data/systems/hospitalAppointment.js +48 -0
  74. package/src/data/systems/hotelBooking.js +59 -0
  75. package/src/data/systems/invoiceBilling.js +19 -0
  76. package/src/data/systems/landingPage.js +29 -0
  77. package/src/data/systems/libraryManagement.js +17 -0
  78. package/src/data/systems/movieBooking.js +49 -0
  79. package/src/data/systems/quizExam.js +31 -0
  80. package/src/data/systems/studentRegistration.js +9 -0
  81. package/src/index.js +22 -0
  82. package/src/main.jsx +10 -0
  83. package/src/styles.css +296 -0
  84. package/styles.css +820 -0
  85. package/utils/systemEngine.js +128 -0
  86. package/vite.config.js +8 -0
  87. package/vite.lib.config.js +27 -0
@@ -0,0 +1,439 @@
1
+ const moduleEnhancementsMap = {
2
+ 'movie-booking': {
3
+ widget: {
4
+ type: 'seat-map',
5
+ title: 'Live Seat Map',
6
+ occupiedSeats: ['A2', 'A3', 'B4', 'B6', 'C1', 'C7', 'D3', 'E5', 'F2']
7
+ },
8
+ presets: [
9
+ {
10
+ label: 'Friday Prime Show',
11
+ data: {
12
+ customerName: 'Mason Clarke',
13
+ movieTitle: 'Dune: Part Two',
14
+ showDate: '2026-05-09',
15
+ showTime: '07:00 PM',
16
+ seats: 4,
17
+ seatType: 'Premium'
18
+ }
19
+ },
20
+ {
21
+ label: 'Late Night Recliner',
22
+ data: {
23
+ customerName: 'Ava Turner',
24
+ movieTitle: 'Interstellar',
25
+ showDate: '2026-05-10',
26
+ showTime: '10:15 PM',
27
+ seats: 2,
28
+ seatType: 'Recliner'
29
+ }
30
+ }
31
+ ]
32
+ },
33
+ 'flight-booking': {
34
+ widget: {
35
+ type: 'route-timeline',
36
+ title: 'Journey Timeline',
37
+ points: ['Chennai', 'Dubai', 'London']
38
+ },
39
+ presets: [
40
+ {
41
+ label: 'Business Route',
42
+ data: {
43
+ passengerName: 'Sophia Walker',
44
+ origin: 'Mumbai',
45
+ destination: 'London',
46
+ travelDate: '2026-06-02',
47
+ passengers: 2,
48
+ cabinClass: 'Business'
49
+ }
50
+ },
51
+ {
52
+ label: 'Economy Family',
53
+ data: {
54
+ passengerName: 'Noah Edwards',
55
+ origin: 'Delhi',
56
+ destination: 'Singapore',
57
+ travelDate: '2026-06-14',
58
+ passengers: 4,
59
+ cabinClass: 'Economy'
60
+ }
61
+ }
62
+ ]
63
+ },
64
+ 'hotel-booking': {
65
+ widget: {
66
+ type: 'occupancy-meter',
67
+ title: 'Property Occupancy',
68
+ percentage: 82
69
+ },
70
+ presets: [
71
+ {
72
+ label: 'Weekend Deluxe',
73
+ data: {
74
+ guestName: 'Liam Harris',
75
+ city: 'Goa',
76
+ checkInDate: '2026-05-22',
77
+ nights: 3,
78
+ roomType: 'Deluxe',
79
+ guests: 2
80
+ }
81
+ },
82
+ {
83
+ label: 'Family Suite',
84
+ data: {
85
+ guestName: 'Emma Collins',
86
+ city: 'Jaipur',
87
+ checkInDate: '2026-06-08',
88
+ nights: 4,
89
+ roomType: 'Suite',
90
+ guests: 4
91
+ }
92
+ }
93
+ ]
94
+ },
95
+ 'event-ticket-booking': {
96
+ widget: {
97
+ type: 'kpi-spark-cards',
98
+ title: 'Event Demand Signals',
99
+ cards: [
100
+ { label: 'Pass Sales', value: '1,920', trend: [4, 5, 6, 8, 9, 11, 10] },
101
+ { label: 'VIP Upgrade', value: '22%', trend: [2, 3, 3, 4, 5, 5, 6] },
102
+ { label: 'Check-in Speed', value: '14 min', trend: [8, 8, 7, 7, 6, 6, 5] }
103
+ ]
104
+ },
105
+ presets: [
106
+ {
107
+ label: 'Tech Summit Day',
108
+ data: {
109
+ attendeeName: 'Lucas Young',
110
+ eventName: 'Tech Summit 2026',
111
+ eventDate: '2026-07-03',
112
+ passes: 3,
113
+ accessZone: 'VIP',
114
+ notes: 'Need front row seating'
115
+ }
116
+ },
117
+ {
118
+ label: 'Concert Crew',
119
+ data: {
120
+ attendeeName: 'Mia Scott',
121
+ eventName: 'Indie Night Live',
122
+ eventDate: '2026-07-11',
123
+ passes: 5,
124
+ accessZone: 'General',
125
+ notes: 'Group booking under same QR batch'
126
+ }
127
+ }
128
+ ]
129
+ },
130
+ 'food-ordering': {
131
+ widget: {
132
+ type: 'kpi-spark-cards',
133
+ title: 'Delivery Performance',
134
+ cards: [
135
+ { label: 'Orders Today', value: '12.4k', trend: [5, 6, 8, 9, 10, 11, 12] },
136
+ { label: 'On-time Rate', value: '93%', trend: [7, 7, 8, 8, 8, 9, 9] },
137
+ { label: 'Avg Basket', value: '$18', trend: [3, 4, 4, 5, 5, 6, 6] }
138
+ ]
139
+ },
140
+ presets: [
141
+ {
142
+ label: 'Lunch Rush',
143
+ data: {
144
+ customerName: 'Olivia Allen',
145
+ restaurant: 'Urban Bowl',
146
+ deliveryDate: '2026-05-01',
147
+ deliveryWindow: '30 mins',
148
+ items: 6,
149
+ deliveryType: 'Express'
150
+ }
151
+ },
152
+ {
153
+ label: 'Dinner Family Pack',
154
+ data: {
155
+ customerName: 'Ethan Campbell',
156
+ restaurant: 'Spice Factory',
157
+ deliveryDate: '2026-05-01',
158
+ deliveryWindow: '60 mins',
159
+ items: 9,
160
+ deliveryType: 'Standard'
161
+ }
162
+ }
163
+ ]
164
+ },
165
+ 'ecommerce-store': {
166
+ widget: {
167
+ type: 'kpi-spark-cards',
168
+ title: 'Store Conversion KPIs',
169
+ cards: [
170
+ { label: 'Sessions', value: '86k', trend: [8, 9, 10, 11, 10, 12, 13] },
171
+ { label: 'Conversion', value: '14.7%', trend: [3, 4, 4, 5, 5, 6, 6] },
172
+ { label: 'AOV', value: '$73', trend: [4, 4, 5, 5, 6, 6, 7] }
173
+ ]
174
+ },
175
+ presets: [
176
+ {
177
+ label: 'Prime Electronics',
178
+ data: {
179
+ customerName: 'Benjamin Hill',
180
+ category: 'Electronics',
181
+ dispatchDate: '2026-05-04',
182
+ quantity: 3,
183
+ deliveryPlan: 'Prime',
184
+ addressNote: 'Office reception before 6 PM'
185
+ }
186
+ },
187
+ {
188
+ label: 'Home Decor Bulk',
189
+ data: {
190
+ customerName: 'Charlotte Green',
191
+ category: 'Home Decor',
192
+ dispatchDate: '2026-05-06',
193
+ quantity: 7,
194
+ deliveryPlan: 'Standard',
195
+ addressNote: 'Call before delivery'
196
+ }
197
+ }
198
+ ]
199
+ },
200
+ 'library-management': {
201
+ widget: {
202
+ type: 'occupancy-meter',
203
+ title: 'Reading Hall Occupancy',
204
+ percentage: 68
205
+ },
206
+ presets: [
207
+ {
208
+ label: 'Scholar Borrow',
209
+ data: {
210
+ librarianName: 'Devika Nair',
211
+ memberName: 'Noah Carter',
212
+ bookCategory: 'Technology',
213
+ issueDate: '2026-05-03',
214
+ borrowDays: 14,
215
+ membershipType: 'Scholar'
216
+ }
217
+ },
218
+ {
219
+ label: 'Premium Long Borrow',
220
+ data: {
221
+ librarianName: 'Arun Das',
222
+ memberName: 'Ivy White',
223
+ bookCategory: 'Business',
224
+ issueDate: '2026-05-07',
225
+ borrowDays: 30,
226
+ membershipType: 'Premium'
227
+ }
228
+ }
229
+ ]
230
+ },
231
+ 'student-registration': {
232
+ widget: {
233
+ type: 'kpi-spark-cards',
234
+ title: 'Enrollment Funnel',
235
+ cards: [
236
+ { label: 'Applications', value: '5,200', trend: [6, 7, 8, 8, 9, 10, 11] },
237
+ { label: 'Verified', value: '92%', trend: [6, 6, 7, 7, 8, 8, 9] },
238
+ { label: 'Avg Turnaround', value: '4.5 min', trend: [9, 8, 8, 7, 7, 6, 6] }
239
+ ]
240
+ },
241
+ presets: [
242
+ {
243
+ label: 'Regular Intake',
244
+ data: {
245
+ studentName: 'Aarav Menon',
246
+ registerNo: 'VIT-26-0301',
247
+ email: 'aarav.menon@example.edu',
248
+ course: 'B.Tech CSE',
249
+ semester: 2,
250
+ registrationType: 'Regular'
251
+ }
252
+ },
253
+ {
254
+ label: 'International Applicant',
255
+ data: {
256
+ studentName: 'Sana Ibrahim',
257
+ registerNo: 'VIT-INT-0412',
258
+ email: 'sana.ibrahim@example.edu',
259
+ course: 'B.Sc Data Science',
260
+ semester: 1,
261
+ registrationType: 'International'
262
+ }
263
+ }
264
+ ]
265
+ },
266
+ 'hospital-appointment': {
267
+ widget: {
268
+ type: 'route-timeline',
269
+ title: 'Care Path Timeline',
270
+ points: ['Triage', 'Consultation', 'Diagnostics', 'Follow-up']
271
+ },
272
+ presets: [
273
+ {
274
+ label: 'Priority Appointment',
275
+ data: {
276
+ patientName: 'Daniel King',
277
+ department: 'Cardiology',
278
+ appointmentDate: '2026-05-05',
279
+ slots: 2,
280
+ consultationMode: 'Priority',
281
+ symptoms: 'Chest discomfort and dizziness'
282
+ }
283
+ },
284
+ {
285
+ label: 'Telehealth Follow-up',
286
+ data: {
287
+ patientName: 'Harper Adams',
288
+ department: 'General Medicine',
289
+ appointmentDate: '2026-05-08',
290
+ slots: 1,
291
+ consultationMode: 'Telehealth',
292
+ symptoms: 'Routine post-treatment review'
293
+ }
294
+ }
295
+ ]
296
+ },
297
+ 'invoice-billing': {
298
+ widget: {
299
+ type: 'kpi-spark-cards',
300
+ title: 'Billing Health Metrics',
301
+ cards: [
302
+ { label: 'Invoices', value: '3,900', trend: [5, 6, 7, 8, 8, 9, 10] },
303
+ { label: 'Collection', value: '94%', trend: [7, 7, 8, 8, 9, 9, 9] },
304
+ { label: 'Avg Amount', value: '$1,280', trend: [4, 5, 5, 6, 6, 7, 7] }
305
+ ]
306
+ },
307
+ presets: [
308
+ {
309
+ label: 'Retainer Invoice',
310
+ data: {
311
+ clientName: 'Northwind Labs',
312
+ serviceType: 'Consulting',
313
+ invoiceDate: '2026-05-01',
314
+ billableUnits: 40,
315
+ billingPlan: 'Retainer',
316
+ memo: 'Monthly strategic advisory retainer'
317
+ }
318
+ },
319
+ {
320
+ label: 'Project Billing',
321
+ data: {
322
+ clientName: 'Skyline Retail',
323
+ serviceType: 'Engineering',
324
+ invoiceDate: '2026-05-12',
325
+ billableUnits: 65,
326
+ billingPlan: 'Project',
327
+ memo: 'Milestone 2 implementation billing'
328
+ }
329
+ }
330
+ ]
331
+ },
332
+ 'chat-messaging': {
333
+ widget: {
334
+ type: 'kpi-spark-cards',
335
+ title: 'Messaging Adoption',
336
+ cards: [
337
+ { label: 'Daily Messages', value: '4.8M', trend: [6, 7, 8, 9, 10, 11, 12] },
338
+ { label: 'Seat Utilization', value: '79%', trend: [5, 6, 6, 7, 7, 8, 8] },
339
+ { label: 'Retention', value: '88%', trend: [6, 6, 7, 7, 8, 8, 9] }
340
+ ]
341
+ },
342
+ presets: [
343
+ {
344
+ label: 'Business Team Launch',
345
+ data: {
346
+ workspaceName: 'Blue Orbit Team',
347
+ teamLead: 'Priya Das',
348
+ activeUsers: 80,
349
+ goLiveDate: '2026-06-01',
350
+ planTier: 'Business',
351
+ supportWindow: 'Extended Hours'
352
+ }
353
+ },
354
+ {
355
+ label: 'Enterprise Rollout',
356
+ data: {
357
+ workspaceName: 'Vertex Global Ops',
358
+ teamLead: 'Lara Bennett',
359
+ activeUsers: 220,
360
+ goLiveDate: '2026-06-15',
361
+ planTier: 'Enterprise',
362
+ supportWindow: '24x7 Support'
363
+ }
364
+ }
365
+ ]
366
+ },
367
+ 'analytics-dashboard': {
368
+ widget: {
369
+ type: 'kpi-spark-cards',
370
+ title: 'Pipeline Trend Cards',
371
+ cards: [
372
+ { label: 'Data Sources', value: '1,100+', trend: [7, 7, 8, 8, 9, 10, 10] },
373
+ { label: 'Refresh Success', value: '99.9%', trend: [8, 8, 8, 9, 9, 9, 9] },
374
+ { label: 'Active Analysts', value: '64', trend: [4, 5, 5, 6, 6, 7, 7] }
375
+ ]
376
+ },
377
+ presets: [
378
+ {
379
+ label: 'Executive KPI Stack',
380
+ data: {
381
+ accountName: 'Growth Intelligence',
382
+ dashboardType: 'Executive KPI',
383
+ dataSources: 16,
384
+ refreshRate: 'Hourly',
385
+ analystSeats: 22,
386
+ subscriptionTier: 'Pro'
387
+ }
388
+ },
389
+ {
390
+ label: 'Finance Control Board',
391
+ data: {
392
+ accountName: 'NorthPeak Finance',
393
+ dashboardType: 'Finance Control',
394
+ dataSources: 32,
395
+ refreshRate: 'Every 6 Hours',
396
+ analystSeats: 40,
397
+ subscriptionTier: 'Elite'
398
+ }
399
+ }
400
+ ]
401
+ },
402
+ 'quiz-exam': {
403
+ widget: {
404
+ type: 'kpi-spark-cards',
405
+ title: 'Assessment Ops',
406
+ cards: [
407
+ { label: 'Exams per Term', value: '860', trend: [5, 6, 6, 7, 7, 8, 8] },
408
+ { label: 'Candidate Load', value: '2,000', trend: [6, 7, 8, 8, 9, 9, 10] },
409
+ { label: 'Integrity Score', value: '97%', trend: [7, 7, 8, 8, 8, 9, 9] }
410
+ ]
411
+ },
412
+ presets: [
413
+ {
414
+ label: 'Proctored Midterm',
415
+ data: {
416
+ instructorName: 'Nina Thomas',
417
+ examTitle: 'Data Structures Midterm',
418
+ examDate: '2026-05-19',
419
+ questionCount: 60,
420
+ candidates: 180,
421
+ examMode: 'Proctored'
422
+ }
423
+ },
424
+ {
425
+ label: 'Certification Batch',
426
+ data: {
427
+ instructorName: 'Rahul Sen',
428
+ examTitle: 'Cloud Practitioner Certification',
429
+ examDate: '2026-06-10',
430
+ questionCount: 90,
431
+ candidates: 420,
432
+ examMode: 'Certification'
433
+ }
434
+ }
435
+ ]
436
+ }
437
+ };
438
+
439
+ export default moduleEnhancementsMap;
@@ -0,0 +1,31 @@
1
+ import MovieBookingModule from './MovieBookingModule';
2
+ import FlightBookingModule from './FlightBookingModule';
3
+ import HotelBookingModule from './HotelBookingModule';
4
+ import EventTicketBookingModule from './EventTicketBookingModule';
5
+ import FoodOrderingModule from './FoodOrderingModule';
6
+ import EcommerceStoreModule from './EcommerceStoreModule';
7
+ import LibraryManagementModule from './LibraryManagementModule';
8
+ import StudentRegistrationModule from './StudentRegistrationModule';
9
+ import HospitalAppointmentModule from './HospitalAppointmentModule';
10
+ import InvoiceBillingModule from './InvoiceBillingModule';
11
+ import ChatMessagingModule from './ChatMessagingModule';
12
+ import AnalyticsDashboardModule from './AnalyticsDashboardModule';
13
+ import QuizExamModule from './QuizExamModule';
14
+
15
+ const systemModuleMap = {
16
+ 'movie-booking': MovieBookingModule,
17
+ 'flight-booking': FlightBookingModule,
18
+ 'hotel-booking': HotelBookingModule,
19
+ 'event-ticket-booking': EventTicketBookingModule,
20
+ 'food-ordering': FoodOrderingModule,
21
+ 'ecommerce-store': EcommerceStoreModule,
22
+ 'library-management': LibraryManagementModule,
23
+ 'student-registration': StudentRegistrationModule,
24
+ 'hospital-appointment': HospitalAppointmentModule,
25
+ 'invoice-billing': InvoiceBillingModule,
26
+ 'chat-messaging': ChatMessagingModule,
27
+ 'analytics-dashboard': AnalyticsDashboardModule,
28
+ 'quiz-exam': QuizExamModule
29
+ };
30
+
31
+ export default systemModuleMap;
@@ -0,0 +1,154 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { buildInitialFormData } from '../../utils/systemEngine';
3
+
4
+ function DynamicSystemForm({ system, onSubmit, presets = [] }) {
5
+ const initialValues = useMemo(() => {
6
+ return buildInitialFormData(system.fields);
7
+ }, [system]);
8
+
9
+ const [formData, setFormData] = useState(initialValues);
10
+
11
+ useEffect(() => {
12
+ setFormData(initialValues);
13
+ }, [initialValues]);
14
+
15
+ const handleChange = (event) => {
16
+ const { name, value, type } = event.target;
17
+
18
+ setFormData((previousData) => ({
19
+ ...previousData,
20
+ [name]: type === 'number' ? Number(value) : value
21
+ }));
22
+ };
23
+
24
+ const handleSubmit = (event) => {
25
+ event.preventDefault();
26
+ onSubmit(formData);
27
+ };
28
+
29
+ const handleApplyPreset = (preset) => {
30
+ if (!preset || !preset.data) {
31
+ return;
32
+ }
33
+
34
+ setFormData((previousData) => ({
35
+ ...previousData,
36
+ ...preset.data
37
+ }));
38
+ };
39
+
40
+ const handleReset = () => {
41
+ setFormData(initialValues);
42
+ };
43
+
44
+ const renderField = (field) => {
45
+ if (field.type === 'select') {
46
+ return (
47
+ <select name={field.name} value={formData[field.name]} onChange={handleChange} required={field.required}>
48
+ {field.options.map((option) => {
49
+ const normalizedOption = typeof option === 'string' ? { label: option, value: option } : option;
50
+
51
+ return (
52
+ <option key={normalizedOption.value} value={normalizedOption.value}>
53
+ {normalizedOption.label}
54
+ </option>
55
+ );
56
+ })}
57
+ </select>
58
+ );
59
+ }
60
+
61
+ if (field.type === 'radio') {
62
+ return (
63
+ <div className="radio-group">
64
+ {field.options.map((option) => {
65
+ const normalizedOption = typeof option === 'string' ? { label: option, value: option } : option;
66
+
67
+ return (
68
+ <label key={normalizedOption.value}>
69
+ <input
70
+ type="radio"
71
+ name={field.name}
72
+ value={normalizedOption.value}
73
+ checked={formData[field.name] === normalizedOption.value}
74
+ onChange={handleChange}
75
+ />
76
+ <span>{normalizedOption.label}</span>
77
+ </label>
78
+ );
79
+ })}
80
+ </div>
81
+ );
82
+ }
83
+
84
+ if (field.type === 'textarea') {
85
+ return (
86
+ <textarea
87
+ name={field.name}
88
+ value={formData[field.name]}
89
+ onChange={handleChange}
90
+ rows={field.rows ?? 4}
91
+ required={field.required}
92
+ placeholder={field.placeholder}
93
+ />
94
+ );
95
+ }
96
+
97
+ return (
98
+ <input
99
+ type={field.type}
100
+ name={field.name}
101
+ value={formData[field.name]}
102
+ onChange={handleChange}
103
+ required={field.required}
104
+ min={field.min}
105
+ max={field.max}
106
+ step={field.step}
107
+ placeholder={field.placeholder}
108
+ />
109
+ );
110
+ };
111
+
112
+ return (
113
+ <section className="form-shell">
114
+ <h3>{system.title} Form</h3>
115
+ <p>Each module has independent fields, pricing logic, and output summary.</p>
116
+
117
+ <div className="form-actions-bar">
118
+ <div className="preset-list">
119
+ {presets.map((preset) => (
120
+ <button
121
+ type="button"
122
+ key={preset.label}
123
+ className="preset-btn"
124
+ onClick={() => handleApplyPreset(preset)}
125
+ >
126
+ {preset.label}
127
+ </button>
128
+ ))}
129
+ </div>
130
+
131
+ <button type="button" className="secondary-btn" onClick={handleReset}>
132
+ Reset Form
133
+ </button>
134
+ </div>
135
+
136
+ <form className="dynamic-form" onSubmit={handleSubmit}>
137
+ <div className="form-grid">
138
+ {system.fields.map((field) => (
139
+ <div className={`field-group ${field.fullWidth ? 'full-width' : ''}`} key={field.name}>
140
+ <label>{field.label}</label>
141
+ {renderField(field)}
142
+ </div>
143
+ ))}
144
+ </div>
145
+
146
+ <button type="submit" className="primary-btn">
147
+ Generate {system.title}
148
+ </button>
149
+ </form>
150
+ </section>
151
+ );
152
+ }
153
+
154
+ export default DynamicSystemForm;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ function SystemHero({ system }) {
4
+ return (
5
+ <section className="system-hero">
6
+ <div>
7
+ <p className="hero-kicker">Template Workspace</p>
8
+ <h2>{system.title}</h2>
9
+ <p>{system.uiStyle}</p>
10
+ </div>
11
+
12
+ <div className="hero-tags">
13
+ {system.highlights.map((highlight) => (
14
+ <span key={highlight}>{highlight}</span>
15
+ ))}
16
+ </div>
17
+ </section>
18
+ );
19
+ }
20
+
21
+ export default SystemHero;
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { formatCurrency } from '../../utils/systemEngine';
3
+
4
+ function SystemSummaryCard({ system, record }) {
5
+ const submittedTime = new Date(record.submittedAt);
6
+ const displayTime = Number.isNaN(submittedTime.valueOf())
7
+ ? 'Recently submitted'
8
+ : submittedTime.toLocaleString();
9
+
10
+ return (
11
+ <section className="summary-shell">
12
+ <div className="summary-head">
13
+ <h3>{system.title} Summary</h3>
14
+ <span>{displayTime}</span>
15
+ </div>
16
+
17
+ <ul className="summary-grid">
18
+ {record.summaryRows.map((row) => (
19
+ <li key={row.label}>
20
+ <small>{row.label}</small>
21
+ <strong>{row.value}</strong>
22
+ </li>
23
+ ))}
24
+ </ul>
25
+
26
+ <div className="price-board">
27
+ <div>
28
+ <span>{record.pricing.quantityLabel}</span>
29
+ <strong>{record.pricing.quantity}</strong>
30
+ </div>
31
+ <div>
32
+ <span>Unit Price</span>
33
+ <strong>{formatCurrency(record.pricing.unitPrice, record.pricing.currency)}</strong>
34
+ </div>
35
+ <div>
36
+ <span>Subtotal</span>
37
+ <strong>{formatCurrency(record.pricing.subtotal, record.pricing.currency)}</strong>
38
+ </div>
39
+ <div>
40
+ <span>Service Fee</span>
41
+ <strong>{formatCurrency(record.pricing.fee, record.pricing.currency)}</strong>
42
+ </div>
43
+ </div>
44
+
45
+ <div className="grand-total">
46
+ <span>{record.pricing.chargeLabel}</span>
47
+ <h4>{formatCurrency(record.pricing.total, record.pricing.currency)}</h4>
48
+ </div>
49
+ </section>
50
+ );
51
+ }
52
+
53
+ export default SystemSummaryCard;