@dashadmin/dash-admin 1.3.51 → 1.3.52
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/dist/components/avatar/Avatar.js +10 -1
- package/dist/components/currency/Format.js +3 -1
- package/dist/components/i18n/BridgedLocalesMenuButton.js +4 -2
- package/dist/components/misc/NoResults.js +3 -1
- package/dist/components/permission/PermissionsSelector.js +34 -14
- package/dist/components/permission/PermissionsSelectorList.js +11 -1
- package/dist/components/selects/RASearchableSelect.js +8 -6
- package/dist/components/selects/RASearchableSelectChips.js +8 -6
- package/dist/components/selects/SearchableSelect.js +8 -6
- package/dist/components/subscription/PlanAddonsSettings.js +88 -17
- package/dist/components/subscription/PlanAuditLog.js +41 -21
- package/dist/components/subscription/PlanFeaturesSettings.js +35 -6
- package/dist/components/subscription/PlanMetadataSettings.js +78 -42
- package/dist/components/subscription/PlanPricesSettings.js +20 -8
- package/dist/components/tenant/TenantSelector.js +8 -6
- package/dist/components/user/UserPreferences.js +77 -22
- package/dist/pages/DASHLightWeightLogin.js +7 -5
- package/dist/pages/Profile.js +5 -3
- package/dist/pages/RecoverPassword.js +28 -14
- package/dist/schemas/subscription/components/SubscriptionPaymentHistory.js +14 -2
- package/dist/schemas/subscription/components/SubscriptionPlanFeatures.js +37 -25
- package/dist/schemas/subscription/components/SubscriptionPlanPreview.js +47 -28
- package/dist/schemas/subscription/components/SubscriptionPlanStats.js +127 -37
- package/package.json +3 -3
- package/src/components/avatar/Avatar.tsx +8 -4
- package/src/components/currency/Format.tsx +8 -6
- package/src/components/i18n/BridgedLocalesMenuButton.tsx +4 -2
- package/src/components/misc/DASHGlobalErrorHandler.tsx +1 -1
- package/src/components/misc/NoResults.tsx +7 -4
- package/src/components/permission/AvailablePermissionsContext.tsx +1 -1
- package/src/components/permission/PermissionsSelector.tsx +48 -33
- package/src/components/permission/PermissionsSelectorList.tsx +7 -2
- package/src/components/selects/RASearchableSelect.tsx +22 -19
- package/src/components/selects/RASearchableSelectChips.tsx +23 -19
- package/src/components/selects/SearchableSelect.tsx +22 -18
- package/src/components/subscription/PlanAddonsSettings.tsx +61 -20
- package/src/components/subscription/PlanAuditLog.tsx +22 -8
- package/src/components/subscription/PlanFeaturesSettings.tsx +28 -8
- package/src/components/subscription/PlanMetadataSettings.tsx +29 -7
- package/src/components/subscription/PlanPricesSettings.tsx +30 -18
- package/src/components/tenant/TenantAttributesContext.tsx +1 -1
- package/src/components/tenant/TenantSelector.tsx +20 -17
- package/src/components/tenant/TenantSettingsContext.tsx +1 -1
- package/src/components/user/UserPreferences.tsx +56 -21
- package/src/contexts/SystemRequestsCache.tsx +1 -1
- package/src/default-theme/menu/AppMenuComponents/expanded/CollapsableSidebarMenu.tsx +3 -3
- package/src/default-theme/menu/SidebarActions.tsx +6 -6
- package/src/pages/DASHLightWeightLogin.tsx +8 -7
- package/src/pages/Profile.tsx +10 -9
- package/src/pages/RecoverPassword.tsx +15 -6
- package/src/schemas/subscription/components/SubscriptionPaymentHistory.tsx +9 -2
- package/src/schemas/subscription/components/SubscriptionPlanFeatures.tsx +10 -3
- package/src/schemas/subscription/components/SubscriptionPlanPreview.tsx +25 -12
- package/src/schemas/subscription/components/SubscriptionPlanStats.tsx +64 -14
- package/src/theme/AppSidebarLogo.tsx +7 -7
|
@@ -128,8 +128,8 @@ const SearchableSelect: React.FC<ISearchableSelect> = ({
|
|
|
128
128
|
};
|
|
129
129
|
|
|
130
130
|
return (
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
<>
|
|
132
|
+
{parsedOptions && (
|
|
133
133
|
<Autocomplete
|
|
134
134
|
key={'autocomplete-' + attribute.attribute}
|
|
135
135
|
multiple={isMultiple}
|
|
@@ -215,7 +215,7 @@ const SearchableSelect: React.FC<ISearchableSelect> = ({
|
|
|
215
215
|
renderInput={(params) => {
|
|
216
216
|
console.log('renderInput', params.id);
|
|
217
217
|
return (
|
|
218
|
-
|
|
218
|
+
<TextField
|
|
219
219
|
key={params.id}
|
|
220
220
|
{...params}
|
|
221
221
|
label={selectLabel}
|
|
@@ -236,26 +236,29 @@ const SearchableSelect: React.FC<ISearchableSelect> = ({
|
|
|
236
236
|
setQ(ev.target.value);
|
|
237
237
|
}*/
|
|
238
238
|
}}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
239
|
+
slotProps={{
|
|
240
|
+
...params.slotProps,
|
|
241
|
+
|
|
242
|
+
input: {
|
|
243
|
+
...params.slotProps.input,
|
|
244
|
+
autoComplete: 'new-password',
|
|
245
|
+
endAdornment: (
|
|
246
|
+
<>
|
|
247
|
+
{isLoading ? (
|
|
248
|
+
<CircularProgress color='inherit' size={20} />
|
|
249
|
+
) : null}
|
|
250
|
+
{params.slotProps.input.endAdornment}
|
|
251
|
+
</>
|
|
252
|
+
),
|
|
253
|
+
}
|
|
254
|
+
}}
|
|
252
255
|
/>
|
|
253
|
-
|
|
256
|
+
);
|
|
254
257
|
}}
|
|
255
258
|
/>
|
|
256
259
|
)}
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
</>
|
|
261
|
+
);
|
|
259
262
|
};
|
|
260
263
|
|
|
261
264
|
const RASearchableSelect = ({
|
|
@@ -195,8 +195,8 @@ export const SearchableSelectChipsControl: React.FC<
|
|
|
195
195
|
}, [parsedOptions])*/
|
|
196
196
|
|
|
197
197
|
return (
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
<>
|
|
199
|
+
{parsedOptions ? (
|
|
200
200
|
<Autocomplete
|
|
201
201
|
key={'autocomplete-' + attribute.attribute}
|
|
202
202
|
multiple={isMultiple}
|
|
@@ -232,7 +232,7 @@ export const SearchableSelectChipsControl: React.FC<
|
|
|
232
232
|
}}
|
|
233
233
|
renderInput={(params) => {
|
|
234
234
|
return (
|
|
235
|
-
|
|
235
|
+
<TextField
|
|
236
236
|
key={params.id}
|
|
237
237
|
{...params}
|
|
238
238
|
label={selectLabel}
|
|
@@ -246,35 +246,39 @@ export const SearchableSelectChipsControl: React.FC<
|
|
|
246
246
|
)
|
|
247
247
|
debounce(() => setQ(searchValue), timerSearch);
|
|
248
248
|
}}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
249
|
+
slotProps={{
|
|
250
|
+
...params.slotProps,
|
|
251
|
+
|
|
252
|
+
input: {
|
|
253
|
+
...params.slotProps.input,
|
|
254
|
+
autoComplete: 'new-password',
|
|
255
|
+
endAdornment: (
|
|
256
|
+
<>
|
|
257
|
+
{isResourceSearchLoading ? (
|
|
258
|
+
<CircularProgress color='inherit' size={20} />
|
|
259
|
+
) : null}
|
|
260
|
+
{params.slotProps.input.endAdornment}
|
|
261
|
+
</>
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
}}
|
|
261
265
|
/>
|
|
262
|
-
|
|
266
|
+
);
|
|
263
267
|
}}
|
|
264
268
|
/>
|
|
265
269
|
) : (
|
|
266
270
|
<LoadingIndicator />
|
|
267
271
|
)}
|
|
268
272
|
|
|
269
|
-
|
|
273
|
+
{!isMultiple && parsedOptions && _defaultValues && (
|
|
270
274
|
<>
|
|
271
275
|
<Chip
|
|
272
276
|
label={renderText(_transformOption(_defaultValues, 'chip'), 'chip')}
|
|
273
277
|
/>
|
|
274
278
|
</>
|
|
275
279
|
)}
|
|
276
|
-
|
|
277
|
-
|
|
280
|
+
</>
|
|
281
|
+
);
|
|
278
282
|
};
|
|
279
283
|
|
|
280
284
|
const RASearchableSelectChips: React.FC<
|
|
@@ -59,10 +59,10 @@ const SearchableSelect: React.FC<any> = ({
|
|
|
59
59
|
// console.log(field.field.value);
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
<>
|
|
63
|
+
<InputLabel>{title}</InputLabel>
|
|
64
|
+
{/*<SearchBar />*/}
|
|
65
|
+
{TrendingUpRounded && (
|
|
66
66
|
<Autocomplete
|
|
67
67
|
multiple={isMultiple}
|
|
68
68
|
loading={isLoading && open}
|
|
@@ -112,24 +112,28 @@ const SearchableSelect: React.FC<any> = ({
|
|
|
112
112
|
}
|
|
113
113
|
}}
|
|
114
114
|
onBlur={() => setQ('')}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
115
|
+
slotProps={{
|
|
116
|
+
...params.slotProps,
|
|
117
|
+
|
|
118
|
+
input: {
|
|
119
|
+
...params.slotProps.input,
|
|
120
|
+
autoComplete: 'new-password',
|
|
121
|
+
endAdornment: (
|
|
122
|
+
<>
|
|
123
|
+
{isLoading ? (
|
|
124
|
+
<CircularProgress color='inherit' size={20} />
|
|
125
|
+
) : null}
|
|
126
|
+
{params.slotProps.input.endAdornment}
|
|
127
|
+
</>
|
|
128
|
+
),
|
|
129
|
+
}
|
|
130
|
+
}}
|
|
127
131
|
/>
|
|
128
132
|
)}
|
|
129
133
|
/>
|
|
130
134
|
)}
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
</>
|
|
136
|
+
);
|
|
133
137
|
};
|
|
134
138
|
|
|
135
139
|
export default SearchableSelect;
|
|
@@ -128,7 +128,9 @@ const AddonRow: React.FC<AddonRowProps> = ({ addonId, entry, plan, mode }) => {
|
|
|
128
128
|
transition: 'border-color 0.3s'
|
|
129
129
|
}}
|
|
130
130
|
>
|
|
131
|
-
<Grid container spacing={2}
|
|
131
|
+
<Grid container spacing={2} sx={{
|
|
132
|
+
alignItems: "flex-start"
|
|
133
|
+
}}>
|
|
132
134
|
{/* Toggle and Label */}
|
|
133
135
|
<Grid item xs={12} md={4}>
|
|
134
136
|
<Controller
|
|
@@ -150,12 +152,16 @@ const AddonRow: React.FC<AddonRowProps> = ({ addonId, entry, plan, mode }) => {
|
|
|
150
152
|
}
|
|
151
153
|
label={
|
|
152
154
|
<Box>
|
|
153
|
-
<Typography variant="subtitle1"
|
|
155
|
+
<Typography variant="subtitle1" sx={{
|
|
156
|
+
fontWeight: "medium"
|
|
157
|
+
}}>
|
|
154
158
|
{entry.icon && <span style={{ marginRight: 8 }}>{entry.icon}</span>}
|
|
155
159
|
{entry.label}
|
|
156
160
|
</Typography>
|
|
157
161
|
{entry.description && (
|
|
158
|
-
<Typography variant="caption"
|
|
162
|
+
<Typography variant="caption" sx={{
|
|
163
|
+
color: "text.secondary"
|
|
164
|
+
}}>
|
|
159
165
|
{entry.description}
|
|
160
166
|
</Typography>
|
|
161
167
|
)}
|
|
@@ -195,17 +201,19 @@ const AddonRow: React.FC<AddonRowProps> = ({ addonId, entry, plan, mode }) => {
|
|
|
195
201
|
type="text"
|
|
196
202
|
size="small"
|
|
197
203
|
disabled={isReadOnly}
|
|
198
|
-
InputProps={{
|
|
199
|
-
startAdornment: (
|
|
200
|
-
<InputAdornment position="start">
|
|
201
|
-
{config.symbol}
|
|
202
|
-
</InputAdornment>
|
|
203
|
-
),
|
|
204
|
-
}}
|
|
205
204
|
sx={{ width: 150 }}
|
|
206
205
|
value={formatPrice(field.value ?? 0, currency)}
|
|
207
206
|
onChange={(e) => handlePriceChange(currency, e.target.value)}
|
|
208
207
|
helperText={config.name}
|
|
208
|
+
slotProps={{
|
|
209
|
+
input: {
|
|
210
|
+
startAdornment: (
|
|
211
|
+
<InputAdornment position="start">
|
|
212
|
+
{config.symbol}
|
|
213
|
+
</InputAdornment>
|
|
214
|
+
),
|
|
215
|
+
}
|
|
216
|
+
}}
|
|
209
217
|
/>
|
|
210
218
|
)}
|
|
211
219
|
/>
|
|
@@ -213,7 +221,13 @@ const AddonRow: React.FC<AddonRowProps> = ({ addonId, entry, plan, mode }) => {
|
|
|
213
221
|
})}
|
|
214
222
|
</Box>
|
|
215
223
|
{plan?.flow_addon_items?.[addonId] && (
|
|
216
|
-
<Typography
|
|
224
|
+
<Typography
|
|
225
|
+
variant="caption"
|
|
226
|
+
sx={{
|
|
227
|
+
color: "text.secondary",
|
|
228
|
+
mt: 1,
|
|
229
|
+
display: 'block'
|
|
230
|
+
}}>
|
|
217
231
|
Flow Item ID: {plan.flow_addon_items[addonId]}
|
|
218
232
|
</Typography>
|
|
219
233
|
)}
|
|
@@ -279,13 +293,23 @@ const PlanAddonsSettingsEdit: React.FC<IDashAutoAdminCustomFieldComponent> = ({
|
|
|
279
293
|
<Typography variant="h6" gutterBottom>
|
|
280
294
|
Plan Add-ons Configuration
|
|
281
295
|
</Typography>
|
|
282
|
-
<Typography
|
|
296
|
+
<Typography
|
|
297
|
+
variant="body2"
|
|
298
|
+
sx={{
|
|
299
|
+
color: "text.secondary",
|
|
300
|
+
mb: 3
|
|
301
|
+
}}>
|
|
283
302
|
Enable add-ons and set prices per currency. Prices are in the smallest currency unit (e.g., cents for USD, pesos for CLP).
|
|
284
303
|
</Typography>
|
|
285
|
-
|
|
304
|
+
|
|
286
305
|
{Object.entries(groupedByTab).map(([tabName, entries]) => (
|
|
287
306
|
<Box key={tabName} sx={{ mb: 4 }}>
|
|
288
|
-
<Typography
|
|
307
|
+
<Typography
|
|
308
|
+
variant="subtitle1"
|
|
309
|
+
sx={{
|
|
310
|
+
fontWeight: "bold",
|
|
311
|
+
mb: 2
|
|
312
|
+
}}>
|
|
289
313
|
{tabName}
|
|
290
314
|
</Typography>
|
|
291
315
|
<Divider sx={{ mb: 2 }} />
|
|
@@ -360,13 +384,23 @@ const PlanAddonsSettingsCreate: React.FC<IDashAutoAdminCustomFieldComponent> = (
|
|
|
360
384
|
<Typography variant="h6" gutterBottom>
|
|
361
385
|
Plan Add-ons Configuration
|
|
362
386
|
</Typography>
|
|
363
|
-
<Typography
|
|
387
|
+
<Typography
|
|
388
|
+
variant="body2"
|
|
389
|
+
sx={{
|
|
390
|
+
color: "text.secondary",
|
|
391
|
+
mb: 3
|
|
392
|
+
}}>
|
|
364
393
|
Enable add-ons and set prices per currency. Prices are in the smallest currency unit.
|
|
365
394
|
</Typography>
|
|
366
|
-
|
|
395
|
+
|
|
367
396
|
{Object.entries(groupedByTab).map(([tabName, entries]) => (
|
|
368
397
|
<Box key={tabName} sx={{ mb: 4 }}>
|
|
369
|
-
<Typography
|
|
398
|
+
<Typography
|
|
399
|
+
variant="subtitle1"
|
|
400
|
+
sx={{
|
|
401
|
+
fontWeight: "bold",
|
|
402
|
+
mb: 2
|
|
403
|
+
}}>
|
|
370
404
|
{tabName}
|
|
371
405
|
</Typography>
|
|
372
406
|
<Divider sx={{ mb: 2 }} />
|
|
@@ -416,10 +450,15 @@ const PlanAddonsSettingsView: React.FC<IDashAutoAdminCustomFieldComponent> = ({
|
|
|
416
450
|
<Typography variant="h6" gutterBottom>
|
|
417
451
|
Plan Add-ons
|
|
418
452
|
</Typography>
|
|
419
|
-
|
|
453
|
+
|
|
420
454
|
{Object.entries(groupedByTab).map(([tabName, entries]) => (
|
|
421
455
|
<Box key={tabName} sx={{ mb: 3 }}>
|
|
422
|
-
<Typography
|
|
456
|
+
<Typography
|
|
457
|
+
variant="subtitle1"
|
|
458
|
+
sx={{
|
|
459
|
+
fontWeight: "bold",
|
|
460
|
+
mb: 2
|
|
461
|
+
}}>
|
|
423
462
|
{tabName}
|
|
424
463
|
</Typography>
|
|
425
464
|
<Divider sx={{ mb: 2 }} />
|
|
@@ -468,7 +507,9 @@ const PlanAddonsSettingsView: React.FC<IDashAutoAdminCustomFieldComponent> = ({
|
|
|
468
507
|
);
|
|
469
508
|
})}
|
|
470
509
|
{flowItemId && (
|
|
471
|
-
<Typography variant="caption"
|
|
510
|
+
<Typography variant="caption" sx={{
|
|
511
|
+
color: "text.secondary"
|
|
512
|
+
}}>
|
|
472
513
|
Flow ID: {flowItemId}
|
|
473
514
|
</Typography>
|
|
474
515
|
)}
|
|
@@ -114,7 +114,12 @@ const JsonDialog: React.FC<JsonDialogProps> = ({ open, log, onClose }) => {
|
|
|
114
114
|
aria-labelledby="audit-log-dialog-title"
|
|
115
115
|
>
|
|
116
116
|
<DialogTitle id="audit-log-dialog-title">
|
|
117
|
-
<Box
|
|
117
|
+
<Box
|
|
118
|
+
sx={{
|
|
119
|
+
display: "flex",
|
|
120
|
+
justifyContent: "space-between",
|
|
121
|
+
alignItems: "center"
|
|
122
|
+
}}>
|
|
118
123
|
<Typography variant="h6">
|
|
119
124
|
Audit Log Details - {log.event || log.description}
|
|
120
125
|
</Typography>
|
|
@@ -129,7 +134,9 @@ const JsonDialog: React.FC<JsonDialogProps> = ({ open, log, onClose }) => {
|
|
|
129
134
|
</Box>
|
|
130
135
|
</DialogTitle>
|
|
131
136
|
<DialogContent dividers>
|
|
132
|
-
<Box
|
|
137
|
+
<Box sx={{
|
|
138
|
+
mb: 2
|
|
139
|
+
}}>
|
|
133
140
|
<Typography variant="subtitle2" color="textSecondary">
|
|
134
141
|
Event Information
|
|
135
142
|
</Typography>
|
|
@@ -318,7 +325,9 @@ const PlanAuditLogView: React.FC<IDashAutoAdminCustomFieldComponent> = ({ resour
|
|
|
318
325
|
return (
|
|
319
326
|
<Paper variant="outlined" sx={{ p: 3, textAlign: 'center' }}>
|
|
320
327
|
<HistoryIcon sx={{ fontSize: 48, color: 'text.secondary', mb: 1 }} />
|
|
321
|
-
<Typography variant="body1"
|
|
328
|
+
<Typography variant="body1" sx={{
|
|
329
|
+
color: "text.secondary"
|
|
330
|
+
}}>
|
|
322
331
|
Save the record first to view audit logs
|
|
323
332
|
</Typography>
|
|
324
333
|
</Paper>
|
|
@@ -343,7 +352,9 @@ const PlanAuditLogView: React.FC<IDashAutoAdminCustomFieldComponent> = ({ resour
|
|
|
343
352
|
return (
|
|
344
353
|
<Paper variant="outlined" sx={{ p: 3, textAlign: 'center' }}>
|
|
345
354
|
<HistoryIcon sx={{ fontSize: 48, color: 'text.secondary', mb: 1 }} />
|
|
346
|
-
<Typography variant="body1"
|
|
355
|
+
<Typography variant="body1" sx={{
|
|
356
|
+
color: "text.secondary"
|
|
357
|
+
}}>
|
|
347
358
|
No audit logs available for this record
|
|
348
359
|
</Typography>
|
|
349
360
|
</Paper>
|
|
@@ -402,9 +413,10 @@ const PlanAuditLogList: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
402
413
|
// For list mode, we just show a placeholder
|
|
403
414
|
// Audit logs are typically viewed in the detail/edit view
|
|
404
415
|
return (
|
|
405
|
-
<Typography variant="body2"
|
|
406
|
-
|
|
407
|
-
|
|
416
|
+
<Typography variant="body2" sx={{
|
|
417
|
+
color: "text.secondary"
|
|
418
|
+
}}>—
|
|
419
|
+
</Typography>
|
|
408
420
|
);
|
|
409
421
|
};
|
|
410
422
|
|
|
@@ -426,7 +438,9 @@ const PlanAuditLog: React.FC<IDashAutoAdminCustomFieldComponent> = (props) => {
|
|
|
426
438
|
return (
|
|
427
439
|
<Paper variant="outlined" sx={{ p: 3, textAlign: 'center' }}>
|
|
428
440
|
<HistoryIcon sx={{ fontSize: 48, color: 'text.secondary', mb: 1 }} />
|
|
429
|
-
<Typography variant="body1"
|
|
441
|
+
<Typography variant="body1" sx={{
|
|
442
|
+
color: "text.secondary"
|
|
443
|
+
}}>
|
|
430
444
|
Audit logs will be available after the record is created
|
|
431
445
|
</Typography>
|
|
432
446
|
</Paper>
|
|
@@ -42,9 +42,13 @@ const PlanFeaturesView: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
42
42
|
|
|
43
43
|
if (!features.length) {
|
|
44
44
|
return (
|
|
45
|
-
<Typography
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
<Typography
|
|
46
|
+
variant="body2"
|
|
47
|
+
sx={{
|
|
48
|
+
color: "text.secondary",
|
|
49
|
+
py: 2
|
|
50
|
+
}}>No features configured
|
|
51
|
+
</Typography>
|
|
48
52
|
);
|
|
49
53
|
}
|
|
50
54
|
|
|
@@ -78,11 +82,17 @@ const PlanFeaturesList: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
78
82
|
const features = record?.features || [];
|
|
79
83
|
|
|
80
84
|
if (!features.length) {
|
|
81
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
<Typography variant="body2" sx={{
|
|
87
|
+
color: "text.secondary"
|
|
88
|
+
}}>—</Typography>
|
|
89
|
+
);
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
return (
|
|
85
|
-
<Stack direction="row" spacing={0.5}
|
|
93
|
+
<Stack direction="row" spacing={0.5} useFlexGap sx={{
|
|
94
|
+
flexWrap: "wrap"
|
|
95
|
+
}}>
|
|
86
96
|
{features.slice(0, 3).map((feature, index) => (
|
|
87
97
|
<Chip
|
|
88
98
|
key={index}
|
|
@@ -151,7 +161,13 @@ const PlanFeaturesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
151
161
|
<Typography variant="subtitle2" gutterBottom>
|
|
152
162
|
Plan Features
|
|
153
163
|
</Typography>
|
|
154
|
-
<Typography
|
|
164
|
+
<Typography
|
|
165
|
+
variant="caption"
|
|
166
|
+
sx={{
|
|
167
|
+
color: "text.secondary",
|
|
168
|
+
display: "block",
|
|
169
|
+
mb: 2
|
|
170
|
+
}}>
|
|
155
171
|
Add feature keys that are enabled for this plan (e.g., "api_access", "custom_branding")
|
|
156
172
|
</Typography>
|
|
157
173
|
|
|
@@ -177,7 +193,9 @@ const PlanFeaturesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
177
193
|
{/* Display current features */}
|
|
178
194
|
{features.length > 0 ? (
|
|
179
195
|
<Paper variant="outlined" sx={{ p: 1 }}>
|
|
180
|
-
<Stack direction="row" spacing={1}
|
|
196
|
+
<Stack direction="row" spacing={1} useFlexGap sx={{
|
|
197
|
+
flexWrap: "wrap"
|
|
198
|
+
}}>
|
|
181
199
|
{features.map((feature, index) => (
|
|
182
200
|
<Chip
|
|
183
201
|
key={index}
|
|
@@ -191,7 +209,9 @@ const PlanFeaturesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
191
209
|
</Stack>
|
|
192
210
|
</Paper>
|
|
193
211
|
) : (
|
|
194
|
-
<Typography variant="body2"
|
|
212
|
+
<Typography variant="body2" sx={{
|
|
213
|
+
color: "text.secondary"
|
|
214
|
+
}}>
|
|
195
215
|
No features added yet
|
|
196
216
|
</Typography>
|
|
197
217
|
)}
|
|
@@ -48,9 +48,13 @@ const PlanMetadataView: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
48
48
|
|
|
49
49
|
if (!entries.length) {
|
|
50
50
|
return (
|
|
51
|
-
<Typography
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
<Typography
|
|
52
|
+
variant="body2"
|
|
53
|
+
sx={{
|
|
54
|
+
color: "text.secondary",
|
|
55
|
+
py: 2
|
|
56
|
+
}}>No metadata configured
|
|
57
|
+
</Typography>
|
|
54
58
|
);
|
|
55
59
|
}
|
|
56
60
|
|
|
@@ -87,7 +91,11 @@ const PlanMetadataList: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
87
91
|
const count = Object.keys(metadata).length;
|
|
88
92
|
|
|
89
93
|
if (!count) {
|
|
90
|
-
return
|
|
94
|
+
return (
|
|
95
|
+
<Typography variant="body2" sx={{
|
|
96
|
+
color: "text.secondary"
|
|
97
|
+
}}>—</Typography>
|
|
98
|
+
);
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
return (
|
|
@@ -177,12 +185,24 @@ const PlanMetadataEdit: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
177
185
|
<Typography variant="subtitle2" gutterBottom>
|
|
178
186
|
Plan Metadata
|
|
179
187
|
</Typography>
|
|
180
|
-
<Typography
|
|
188
|
+
<Typography
|
|
189
|
+
variant="caption"
|
|
190
|
+
sx={{
|
|
191
|
+
color: "text.secondary",
|
|
192
|
+
display: "block",
|
|
193
|
+
mb: 2
|
|
194
|
+
}}>
|
|
181
195
|
Add key-value pairs for additional plan configuration
|
|
182
196
|
</Typography>
|
|
183
197
|
|
|
184
198
|
{/* Add new pair input */}
|
|
185
|
-
<Stack
|
|
199
|
+
<Stack
|
|
200
|
+
direction="row"
|
|
201
|
+
spacing={1}
|
|
202
|
+
sx={{
|
|
203
|
+
alignItems: "flex-start",
|
|
204
|
+
mb: 2
|
|
205
|
+
}}>
|
|
186
206
|
<TextField
|
|
187
207
|
value={newKey}
|
|
188
208
|
onChange={(e) => {
|
|
@@ -252,7 +272,9 @@ const PlanMetadataEdit: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
252
272
|
</Table>
|
|
253
273
|
</TableContainer>
|
|
254
274
|
) : (
|
|
255
|
-
<Typography variant="body2"
|
|
275
|
+
<Typography variant="body2" sx={{
|
|
276
|
+
color: "text.secondary"
|
|
277
|
+
}}>
|
|
256
278
|
No metadata added yet
|
|
257
279
|
</Typography>
|
|
258
280
|
)}
|
|
@@ -69,9 +69,10 @@ const PlanPricesView: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
69
69
|
|
|
70
70
|
if (!prices || Object.keys(prices).length === 0) {
|
|
71
71
|
return (
|
|
72
|
-
<Typography variant="body2"
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
<Typography variant="body2" sx={{
|
|
73
|
+
color: "text.secondary"
|
|
74
|
+
}}>No prices configured
|
|
75
|
+
</Typography>
|
|
75
76
|
);
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -101,7 +102,9 @@ const PlanPricesView: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
101
102
|
color={currency?.is_default ? 'primary' : 'default'}
|
|
102
103
|
/>
|
|
103
104
|
{currency?.is_default && (
|
|
104
|
-
<Typography variant="caption"
|
|
105
|
+
<Typography variant="caption" sx={{
|
|
106
|
+
color: "text.secondary"
|
|
107
|
+
}}>
|
|
105
108
|
(Default)
|
|
106
109
|
</Typography>
|
|
107
110
|
)}
|
|
@@ -127,7 +130,11 @@ const PlanPricesList: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
|
|
|
127
130
|
const prices = plan?.prices;
|
|
128
131
|
|
|
129
132
|
if (!prices || Object.keys(prices).length === 0) {
|
|
130
|
-
return
|
|
133
|
+
return (
|
|
134
|
+
<Typography variant="body2" sx={{
|
|
135
|
+
color: "text.secondary"
|
|
136
|
+
}}>—</Typography>
|
|
137
|
+
);
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
return (
|
|
@@ -215,18 +222,21 @@ const PlanPricesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = ({ method }
|
|
|
215
222
|
|
|
216
223
|
if (!currencies || currencies.length === 0) {
|
|
217
224
|
return (
|
|
218
|
-
<Typography variant="body2"
|
|
219
|
-
|
|
220
|
-
|
|
225
|
+
<Typography variant="body2" sx={{
|
|
226
|
+
color: "text.secondary"
|
|
227
|
+
}}>No currencies available. Please configure currencies first.
|
|
228
|
+
</Typography>
|
|
221
229
|
);
|
|
222
230
|
}
|
|
223
231
|
|
|
224
232
|
return (
|
|
225
233
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
226
|
-
<Typography variant="subtitle2"
|
|
234
|
+
<Typography variant="subtitle2" sx={{
|
|
235
|
+
color: "text.secondary"
|
|
236
|
+
}}>
|
|
227
237
|
Set the price for each available currency (in cents/smallest unit)
|
|
228
238
|
</Typography>
|
|
229
|
-
|
|
239
|
+
|
|
230
240
|
{currencies.map((currency) => {
|
|
231
241
|
const currentValue = currentPrices[currency.code] ?? '';
|
|
232
242
|
|
|
@@ -237,13 +247,6 @@ const PlanPricesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = ({ method }
|
|
|
237
247
|
type="number"
|
|
238
248
|
value={currentValue}
|
|
239
249
|
onChange={(e) => handlePriceChange(currency.code, e.target.value)}
|
|
240
|
-
InputProps={{
|
|
241
|
-
startAdornment: (
|
|
242
|
-
<InputAdornment position="start">
|
|
243
|
-
{currency.symbol}
|
|
244
|
-
</InputAdornment>
|
|
245
|
-
),
|
|
246
|
-
}}
|
|
247
250
|
helperText={
|
|
248
251
|
currency.format
|
|
249
252
|
? `Format: ${currency.format} • Example: ${currency.symbol}${numeral(29900).format(currency.format)}`
|
|
@@ -259,10 +262,19 @@ const PlanPricesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = ({ method }
|
|
|
259
262
|
}
|
|
260
263
|
} : {}
|
|
261
264
|
}}
|
|
265
|
+
slotProps={{
|
|
266
|
+
input: {
|
|
267
|
+
startAdornment: (
|
|
268
|
+
<InputAdornment position="start">
|
|
269
|
+
{currency.symbol}
|
|
270
|
+
</InputAdornment>
|
|
271
|
+
),
|
|
272
|
+
}
|
|
273
|
+
}}
|
|
262
274
|
/>
|
|
263
275
|
);
|
|
264
276
|
})}
|
|
265
|
-
|
|
277
|
+
|
|
266
278
|
{/* Hidden input to ensure prices gets submitted */}
|
|
267
279
|
<input
|
|
268
280
|
type="hidden"
|