umwd-components 0.1.836 → 0.1.837

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.
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ /*
3
+ * UMWD-Components
4
+ * @copyright Jelle Paulus
5
+ * @license MIT
6
+ */
7
+
8
+ import { jsx, Fragment } from 'react/jsx-runtime';
9
+ import { isModuleEnabled, isModuleFeatureEnabled } from '../../../lib/module-config/config.js';
10
+
11
+ /**
12
+ * Component that conditionally renders children based on module/feature enablement
13
+ */
14
+ function ModuleGuard({ module, feature, fallback = null, children, }) {
15
+ const moduleEnabled = isModuleEnabled(module);
16
+ if (!moduleEnabled) {
17
+ return jsx(Fragment, { children: fallback });
18
+ }
19
+ if (feature) {
20
+ const featureEnabled = isModuleFeatureEnabled(module, feature);
21
+ if (!featureEnabled) {
22
+ return jsx(Fragment, { children: fallback });
23
+ }
24
+ }
25
+ return jsx(Fragment, { children: children });
26
+ }
27
+ /**
28
+ * Render prop component that provides module/feature status to children
29
+ */
30
+ function ConditionalModule({ module, feature, children, }) {
31
+ const moduleEnabled = isModuleEnabled(module);
32
+ const featureEnabled = feature
33
+ ? isModuleFeatureEnabled(module, feature)
34
+ : true;
35
+ const isEnabled = moduleEnabled && featureEnabled;
36
+ return jsx(Fragment, { children: children(isEnabled) });
37
+ }
38
+
39
+ export { ConditionalModule, ModuleGuard };
@@ -223,3 +223,6 @@ export { MinioItemList } from './components/common/media/minio/MinioItemList.js'
223
223
  export { MinioDisplay } from './components/common/media/minio/MinioDisplay.js';
224
224
  export { contactFormAction } from './data/actions/e-commerce/lead/contactFormAction.js';
225
225
  export { ShippingStatusIndicator } from './components/e-commerce/opo/ShippingStatusIndicator.js';
226
+ export { clearConfigCache, getConfigFilePath, getEnabledModules, getFullConfig, getModuleConfig, isModuleEnabled, isModuleFeatureEnabled, validateCurrentConfig } from './lib/module-config/config.js';
227
+ export { filterNavigationByModules } from './lib/module-config/navigation-filter.js';
228
+ export { ConditionalModule, ModuleGuard } from './components/common/module-config/ModuleGuard.js';
@@ -0,0 +1,207 @@
1
+ /*
2
+ * UMWD-Components
3
+ * @copyright Jelle Paulus
4
+ * @license MIT
5
+ */
6
+
7
+ import { readFileSync } from 'fs';
8
+ import { join } from 'path';
9
+
10
+ let cachedConfig = null;
11
+ /**
12
+ * Get the path to the umwdconfig.json file
13
+ * This function works across different environments (frontend, backend, CMS)
14
+ */
15
+ function getConfigPath() {
16
+ // Start from the current working directory
17
+ let currentPath = process.cwd();
18
+ // For apps in subdirectories, traverse up to find the root config
19
+ const possiblePaths = [
20
+ join(currentPath, "umwdconfig.json"), // Root level
21
+ join(currentPath, "..", "umwdconfig.json"), // One level up (for frontend/backend/cms)
22
+ join(currentPath, "..", "..", "umwdconfig.json"), // Two levels up
23
+ join(currentPath, "..", "..", "..", "umwdconfig.json"), // Three levels up
24
+ ];
25
+ for (const path of possiblePaths) {
26
+ try {
27
+ // Check if file exists by trying to read it
28
+ readFileSync(path, "utf8");
29
+ return path;
30
+ }
31
+ catch {
32
+ // File doesn't exist, continue to next path
33
+ continue;
34
+ }
35
+ }
36
+ throw new Error("umwdconfig.json not found. Please ensure the configuration file exists in the project root.\n" +
37
+ `Searched paths:\n${possiblePaths.map((p) => ` - ${p}`).join("\n")}`);
38
+ }
39
+ /**
40
+ * Validate the UMWD configuration object
41
+ */
42
+ function validateConfig(config) {
43
+ const errors = [];
44
+ if (!config || typeof config !== "object") {
45
+ return {
46
+ isValid: false,
47
+ errors: [{ field: "root", message: "Configuration must be a valid object" }]
48
+ };
49
+ }
50
+ if (!config.modules || typeof config.modules !== "object") {
51
+ errors.push({ field: "modules", message: "modules field is required and must be an object" });
52
+ }
53
+ else {
54
+ // Validate required modules
55
+ const requiredModules = ["pageBuilder", "ecommerce"];
56
+ for (const module of requiredModules) {
57
+ if (!config.modules[module]) {
58
+ errors.push({ field: `modules.${module}`, message: `${module} module configuration is required` });
59
+ }
60
+ else if (typeof config.modules[module] !== "object") {
61
+ errors.push({ field: `modules.${module}`, message: `${module} module must be an object` });
62
+ }
63
+ else if (typeof config.modules[module].enabled !== "boolean") {
64
+ errors.push({ field: `modules.${module}.enabled`, message: `${module}.enabled must be a boolean` });
65
+ }
66
+ }
67
+ // Validate optional features within modules
68
+ Object.keys(config.modules).forEach(moduleName => {
69
+ const module = config.modules[moduleName];
70
+ if (module && module.features && typeof module.features !== "object") {
71
+ errors.push({ field: `modules.${moduleName}.features`, message: `${moduleName}.features must be an object` });
72
+ }
73
+ else if (module && module.features) {
74
+ Object.keys(module.features).forEach(featureName => {
75
+ if (typeof module.features[featureName] !== "boolean") {
76
+ errors.push({
77
+ field: `modules.${moduleName}.features.${featureName}`,
78
+ message: `${moduleName}.features.${featureName} must be a boolean`
79
+ });
80
+ }
81
+ });
82
+ }
83
+ });
84
+ }
85
+ return {
86
+ isValid: errors.length === 0,
87
+ errors
88
+ };
89
+ }
90
+ /**
91
+ * Load and parse the UMWD configuration file
92
+ */
93
+ function loadConfig(useCache = true) {
94
+ if (useCache && cachedConfig) {
95
+ return cachedConfig;
96
+ }
97
+ try {
98
+ const configPath = getConfigPath();
99
+ const configContent = readFileSync(configPath, "utf8");
100
+ const config = JSON.parse(configContent);
101
+ const validation = validateConfig(config);
102
+ if (!validation.isValid) {
103
+ const errorMessages = validation.errors.map(error => `${error.field}: ${error.message}`).join(", ");
104
+ throw new Error(`Invalid UMWD configuration: ${errorMessages}`);
105
+ }
106
+ cachedConfig = config;
107
+ return cachedConfig;
108
+ }
109
+ catch (error) {
110
+ if (error instanceof SyntaxError) {
111
+ throw new Error("Invalid JSON in umwdconfig.json file. Please check the file syntax.");
112
+ }
113
+ throw error;
114
+ }
115
+ }
116
+ /**
117
+ * Get the configuration for a specific module
118
+ */
119
+ function getModuleConfig(moduleName) {
120
+ const config = loadConfig();
121
+ if (!config.modules[moduleName]) {
122
+ throw new Error(`Module '${moduleName}' not found in configuration`);
123
+ }
124
+ return config.modules[moduleName];
125
+ }
126
+ /**
127
+ * Check if a specific module is enabled
128
+ */
129
+ function isModuleEnabled(moduleName) {
130
+ try {
131
+ const moduleConfig = getModuleConfig(moduleName);
132
+ return moduleConfig ? moduleConfig.enabled : false;
133
+ }
134
+ catch {
135
+ // If module doesn't exist or config is invalid, assume it's disabled
136
+ return false;
137
+ }
138
+ }
139
+ /**
140
+ * Check if a specific feature within a module is enabled
141
+ */
142
+ function isModuleFeatureEnabled(moduleName, featureName) {
143
+ try {
144
+ const moduleConfig = getModuleConfig(moduleName);
145
+ // If module doesn't exist or is disabled, all features are disabled
146
+ if (!moduleConfig || !moduleConfig.enabled) {
147
+ return false;
148
+ }
149
+ // If no features are defined, assume the feature is enabled (if module is enabled)
150
+ if (!moduleConfig.features) {
151
+ return true;
152
+ }
153
+ // Check if the specific feature is enabled
154
+ return moduleConfig.features[featureName] === true;
155
+ }
156
+ catch {
157
+ // If module doesn't exist or config is invalid, assume feature is disabled
158
+ return false;
159
+ }
160
+ }
161
+ /**
162
+ * Get the full configuration object
163
+ */
164
+ function getFullConfig() {
165
+ return loadConfig();
166
+ }
167
+ /**
168
+ * Get all enabled modules
169
+ */
170
+ function getEnabledModules() {
171
+ const config = loadConfig();
172
+ return Object.keys(config.modules).filter(moduleName => {
173
+ const moduleConfig = config.modules[moduleName];
174
+ return moduleConfig && moduleConfig.enabled;
175
+ });
176
+ }
177
+ /**
178
+ * Validate the current configuration without throwing
179
+ */
180
+ function validateCurrentConfig() {
181
+ try {
182
+ const configPath = getConfigPath();
183
+ const configContent = readFileSync(configPath, "utf8");
184
+ const config = JSON.parse(configContent);
185
+ return validateConfig(config);
186
+ }
187
+ catch (error) {
188
+ return {
189
+ isValid: false,
190
+ errors: [{ field: "file", message: error instanceof Error ? error.message : "Unknown error" }]
191
+ };
192
+ }
193
+ }
194
+ /**
195
+ * Clear the configuration cache (useful for testing or dynamic config reloading)
196
+ */
197
+ function clearConfigCache() {
198
+ cachedConfig = null;
199
+ }
200
+ /**
201
+ * Get the path to the configuration file (useful for debugging)
202
+ */
203
+ function getConfigFilePath() {
204
+ return getConfigPath();
205
+ }
206
+
207
+ export { clearConfigCache, getConfigFilePath, getEnabledModules, getFullConfig, getModuleConfig, isModuleEnabled, isModuleFeatureEnabled, validateCurrentConfig };
@@ -0,0 +1,58 @@
1
+ /*
2
+ * UMWD-Components
3
+ * @copyright Jelle Paulus
4
+ * @license MIT
5
+ */
6
+
7
+ import { isModuleEnabled, isModuleFeatureEnabled } from './config.js';
8
+
9
+ /**
10
+ * Filter navigation items based on enabled modules and features
11
+ */
12
+ function filterNavigationByModules(navigation) {
13
+ return navigation
14
+ .filter((item) => {
15
+ // Check if this is an e-commerce related navigation item
16
+ if (item.href && isECommerceRoute(item.href)) {
17
+ if (!isModuleEnabled("ecommerce")) {
18
+ return false;
19
+ }
20
+ // Check for specific e-commerce features
21
+ if (item.href.includes("/user/orders") ||
22
+ item.href.includes("/user/returns")) {
23
+ return isModuleFeatureEnabled("ecommerce", "orders");
24
+ }
25
+ if (item.href.includes("/shop")) {
26
+ return isModuleFeatureEnabled("ecommerce", "shopping");
27
+ }
28
+ }
29
+ return true;
30
+ })
31
+ .map((item) => {
32
+ // Process children for items that passed the filter
33
+ if (item.children) {
34
+ return {
35
+ ...item,
36
+ children: filterNavigationByModules(item.children)
37
+ };
38
+ }
39
+ return item;
40
+ });
41
+ }
42
+ /**
43
+ * Check if a route is e-commerce related
44
+ */
45
+ function isECommerceRoute(href) {
46
+ const ecommercePatterns = [
47
+ "/shop",
48
+ "/user/orders",
49
+ "/user/returns",
50
+ "/user/profile",
51
+ "/cart",
52
+ "/checkout",
53
+ "/check-out"
54
+ ];
55
+ return ecommercePatterns.some(pattern => href.startsWith(pattern));
56
+ }
57
+
58
+ export { filterNavigationByModules };