tee3apps-cms-sdk-react 0.0.10 → 0.0.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tee3apps-cms-sdk-react",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Uses JSON to dynamically generate and render UI pages in a website",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -10,6 +10,7 @@ import RadioField from './RadioField';
10
10
  import SelectField from './SelectField';
11
11
  import ImageComponent from './ImageComponent';
12
12
  import TermsAndCondition from './TermsAndCondition';
13
+ import { Linodeurl } from '../const';
13
14
 
14
15
  interface BoxRendererProps {
15
16
  box: Box;
@@ -64,7 +65,7 @@ const BoxRenderer: React.FC<BoxRendererProps> = ({
64
65
  return box.props.mode.tablet || {};
65
66
  case 'web':
66
67
  default:
67
- return box.props.mode.web;
68
+ return box.props.mode.web || {};
68
69
  }
69
70
  };
70
71
 
@@ -80,6 +81,58 @@ const BoxRenderer: React.FC<BoxRendererProps> = ({
80
81
  const currentMode = getCurrentMode();
81
82
  const widthPercentage = (colspan / totalColumns) * 100;
82
83
 
84
+ // Handle content justification with proper CSS values (from BoxComponent)
85
+ const getJustifyContent = (justify: string): React.CSSProperties['justifyContent'] => {
86
+ if (justify === 'initial') return 'initial';
87
+
88
+ const justifyMap: Record<string, React.CSSProperties['justifyContent']> = {
89
+ around: 'space-around',
90
+ between: 'space-between',
91
+ evenly: 'space-evenly',
92
+ start: 'flex-start',
93
+ end: 'flex-end',
94
+ center: 'center',
95
+ 'flex-start': 'flex-start',
96
+ };
97
+
98
+ return justifyMap[justify] || justify || 'flex-start';
99
+ };
100
+
101
+ // Handle alignment with proper CSS values (from BoxComponent)
102
+ const getAlignItems = (align: string): React.CSSProperties['alignItems'] => {
103
+ if (align === 'initial') return 'initial';
104
+
105
+ const alignMap: Record<string, React.CSSProperties['alignItems']> = {
106
+ start: 'flex-start',
107
+ end: 'flex-end',
108
+ center: 'center',
109
+ stretch: 'stretch',
110
+ baseline: 'baseline',
111
+ 'flex-start': 'flex-start',
112
+ };
113
+
114
+ return (typeof align === 'string' && alignMap[align]) || align || 'flex-start';
115
+ };
116
+
117
+ // Build background image URL with Linode URL prefix
118
+ const getBackgroundImageUrl = () => {
119
+ if (!box.props.bgImage) return 'none';
120
+
121
+ const bgImage = box.props.bgImage;
122
+ // If the image URL already starts with http:// or https://, use it as is
123
+ if (typeof bgImage === 'string' && (bgImage.startsWith('http://') || bgImage.startsWith('https://'))) {
124
+ return `url(${bgImage})`;
125
+ }
126
+ // Otherwise, prepend the Linode URL
127
+ return `url(${Linodeurl}${bgImage})`;
128
+ };
129
+
130
+ // Determine if flexbox should be used
131
+ const useFlexView = currentMode.flexView !== false; // Default to true if not specified
132
+
133
+ // Handle overflow/scroll
134
+ const overflowStyle = currentMode.isScroll ? 'auto' : 'hidden';
135
+
83
136
  // Dynamic height calculation based on content type
84
137
  const getBoxHeight = () => {
85
138
  if (!autoAdjustForImages) {
@@ -101,28 +154,40 @@ const BoxRenderer: React.FC<BoxRendererProps> = ({
101
154
  <div
102
155
  style={{
103
156
  backgroundColor: box.props.bgColor,
104
- display: currentMode.isVisible !== false ? 'block' : 'none',
157
+ backgroundImage: getBackgroundImageUrl(),
105
158
  backgroundSize: box.props.bgsize || 'cover',
159
+ backgroundPosition: 'center',
160
+ display: currentMode.isVisible !== false ? (useFlexView ? 'flex' : 'block') : 'none',
106
161
  height: getBoxHeight(),
107
162
  minHeight: autoAdjustForImages ? 'auto' : (currentMode.height || 'auto'),
108
163
  borderRadius: currentMode.radius || '0px',
109
164
  width: `${widthPercentage}%`,
110
165
  float: 'left',
111
166
  boxSizing: 'border-box',
112
- padding: 'px',
167
+ padding: '5px',
113
168
  margin: 0,
114
- overflow: 'hidden',
115
- position: 'relative'
169
+ marginTop: currentMode.top,
170
+ marginBottom: currentMode.bottom,
171
+ marginLeft: currentMode.left,
172
+ marginRight: currentMode.right,
173
+ overflow: overflowStyle,
174
+ position: 'relative',
175
+ // Flexbox properties when flexView is enabled
176
+ ...(useFlexView && {
177
+ flexDirection: 'column',
178
+ alignItems: box.props.align === 'initial' ? 'initial' : getAlignItems(box.props.align),
179
+ justifyContent: box.props.justify === 'initial' ? 'initial' : getJustifyContent(box.props.justify),
180
+ }),
116
181
  }}
117
182
  >
118
183
  <div style={{
119
184
  width: '100%',
120
185
  height: autoAdjustForImages ? 'auto' : '100%',
121
- display: 'flex',
186
+ display: useFlexView ? 'flex' : 'block',
122
187
  flexDirection: 'column',
123
- alignItems: box.props.align || 'flex-start',
124
- justifyContent: box.props.justify || 'flex-start',
125
- padding: 0,
188
+ alignItems: useFlexView ? (box.props.align === 'initial' ? 'initial' : getAlignItems(box.props.align)) : undefined,
189
+ justifyContent: useFlexView ? (box.props.justify === 'initial' ? 'initial' : getJustifyContent(box.props.justify)) : undefined,
190
+ padding: '5px',
126
191
  margin: 0,
127
192
  boxSizing: 'border-box'
128
193
  }}>
@@ -218,7 +283,7 @@ const BoxRenderer: React.FC<BoxRendererProps> = ({
218
283
  );
219
284
  } else if (component.name === 'TextComponent') {
220
285
  return <TextComponent key={index} props={component.props} />;
221
- } else if (component.name === 'TermsAndCondition' || component.name === 'TERMSANDCONDITION') {
286
+ } else if (component.name === 'TermsAndCondition' ) {
222
287
  const code = getFieldCode(component);
223
288
  const hasError = validationErrors[code];
224
289
  return (
@@ -85,7 +85,11 @@ const Button: React.FC<ButtonProps> = ({
85
85
  };
86
86
 
87
87
  // Handle button click based on button type
88
- const handleClick = () => {
88
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
89
+ // Prevent default form submission behavior
90
+ e.preventDefault();
91
+ e.stopPropagation();
92
+
89
93
  const buttonType = props.buttonType || 'submit';
90
94
 
91
95
  // Handle different button types
@@ -145,7 +149,7 @@ const Button: React.FC<ButtonProps> = ({
145
149
  <div className="mb-6">
146
150
  <button
147
151
  onClick={handleClick}
148
- type={props.buttonType === 'submit' ? 'submit' : 'button'}
152
+ type="button"
149
153
  disabled={props.disabled || (isSubmitting && props.buttonType === 'submit')}
150
154
  style={{
151
155
  backgroundColor: currentMode.bgColor || '#3498db',
@@ -209,7 +209,8 @@ const PageForm: React.FC<PageFormProps> = ({ jsonData, onSubmit, isUrl = false,
209
209
  const transformedData = transformFormValuesToNames();
210
210
 
211
211
  // Check if we should send to URL or use onSubmit callback
212
- if (isUrl && url) {
212
+ // If URL is provided, automatically use it for API submission
213
+ if (url && url.trim() !== '') {
213
214
  // Send data to API URL
214
215
  setIsSubmitting(true);
215
216
  try {
@@ -223,13 +224,17 @@ const PageForm: React.FC<PageFormProps> = ({ jsonData, onSubmit, isUrl = false,
223
224
 
224
225
  // For GET requests, append data as query parameters
225
226
  // For POST requests, send data in the body
226
- let requestUrl = url;
227
+ let requestUrl = url.trim();
227
228
  if (httpMethod === 'GET') {
228
229
  const queryParams = new URLSearchParams();
229
230
  Object.keys(transformedData).forEach((key) => {
230
- queryParams.append(key, String(transformedData[key]));
231
+ const value = transformedData[key];
232
+ if (value !== null && value !== undefined && value !== '') {
233
+ queryParams.append(key, String(value));
234
+ }
231
235
  });
232
- requestUrl = `${url}?${queryParams.toString()}`;
236
+ const queryString = queryParams.toString();
237
+ requestUrl = queryString ? `${requestUrl}?${queryString}` : requestUrl;
233
238
  } else {
234
239
  // POST, PUT, PATCH, etc.
235
240
  requestOptions.body = JSON.stringify(transformedData);
@@ -237,11 +242,28 @@ const PageForm: React.FC<PageFormProps> = ({ jsonData, onSubmit, isUrl = false,
237
242
 
238
243
  const response = await fetch(requestUrl, requestOptions);
239
244
 
245
+ // Read response as text first (can only read body once)
246
+ const responseText = await response.text().catch(() => '');
247
+
240
248
  if (!response.ok) {
241
- throw new Error(`HTTP error! status: ${response.status}`);
249
+ const errorText = responseText || response.statusText || `HTTP ${response.status}`;
250
+ throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
242
251
  }
243
252
 
244
- const responseData = await response.json().catch(() => response.text());
253
+ // Try to parse as JSON, fallback to text if not JSON
254
+ let responseData;
255
+ const contentType = response.headers.get('content-type');
256
+ if (contentType && contentType.includes('application/json') && responseText) {
257
+ try {
258
+ responseData = JSON.parse(responseText);
259
+ } catch {
260
+ // If JSON parsing fails, use text as message
261
+ responseData = { message: responseText };
262
+ }
263
+ } else {
264
+ // Not JSON or empty response, use text as message
265
+ responseData = responseText ? { message: responseText } : { message: 'Success' };
266
+ }
245
267
 
246
268
  setIsSubmitting(false);
247
269
  showToast('Form submitted successfully!', 'success');
@@ -253,6 +275,7 @@ const PageForm: React.FC<PageFormProps> = ({ jsonData, onSubmit, isUrl = false,
253
275
  } catch (error) {
254
276
  setIsSubmitting(false);
255
277
  const errorMessage = error instanceof Error ? error.message : 'Failed to submit form';
278
+ console.error('Form submission error:', error);
256
279
  showToast(`Error submitting form: ${errorMessage}`, 'error');
257
280
 
258
281
  // Still call onSubmit with error data if provided
@@ -264,6 +287,9 @@ const PageForm: React.FC<PageFormProps> = ({ jsonData, onSubmit, isUrl = false,
264
287
  // Send transformed data back to parent component via onSubmit callback
265
288
  if (onSubmit) {
266
289
  onSubmit(transformedData);
290
+ } else {
291
+ // If neither URL nor onSubmit is provided, show a warning
292
+ showToast('No submission handler configured. Please provide either a URL or onSubmit callback.', 'warning');
267
293
  }
268
294
  }
269
295
  }, [formValues, validateForm, getRequiredFields, transformFormValuesToNames, onSubmit, showToast, isUrl, method, url]);
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import BoxRenderer from './BoxRenderer';
3
3
  import type { Row } from '../types';
4
+ import { Linodeurl } from '../const';
4
5
 
5
6
  interface RowComponentProps {
6
7
  row: Row;
@@ -35,18 +36,72 @@ const RowComponent: React.FC<RowComponentProps> = ({
35
36
  return row.props.mode.tablet || {};
36
37
  case 'web':
37
38
  default:
38
- return row.props.mode.web;
39
+ return row.props.mode.web || {};
39
40
  }
40
41
  };
41
42
 
42
43
  const currentMode = getCurrentMode();
44
+
45
+ // Determine if flexbox should be used
46
+ const useFlexView = currentMode.flexView !== false; // Default to true if not specified
47
+
48
+ // Handle overflow/scroll
49
+ const overflowStyle = currentMode.isScroll ? 'auto' : 'hidden';
50
+
51
+ // Handle content justification with proper CSS values (from BoxComponent)
52
+ const getJustifyContent = (justify: string): React.CSSProperties['justifyContent'] => {
53
+ if (justify === 'initial') return 'initial';
54
+
55
+ const justifyMap: Record<string, React.CSSProperties['justifyContent']> = {
56
+ around: 'space-around',
57
+ between: 'space-between',
58
+ evenly: 'space-evenly',
59
+ start: 'flex-start',
60
+ end: 'flex-end',
61
+ center: 'center',
62
+ 'flex-start': 'flex-start',
63
+ 'flex-end': 'flex-end',
64
+ };
65
+
66
+ return justifyMap[justify] || justify || 'flex-start';
67
+ };
68
+
69
+ // Handle alignment with proper CSS values (from BoxComponent)
70
+ const getAlignItems = (align: string): React.CSSProperties['alignItems'] => {
71
+ if (align === 'initial') return 'initial';
72
+
73
+ const alignMap: Record<string, React.CSSProperties['alignItems']> = {
74
+ start: 'flex-start',
75
+ end: 'flex-end',
76
+ center: 'center',
77
+ stretch: 'stretch',
78
+ baseline: 'baseline',
79
+ 'flex-start': 'flex-start',
80
+ 'flex-end': 'flex-end',
81
+ };
82
+
83
+ return (typeof align === 'string' && alignMap[align]) || align || 'flex-start';
84
+ };
85
+
86
+ // Build background image URL with Linode URL prefix
87
+ const getBackgroundImageUrl = () => {
88
+ if (!row.props.bgImage) return 'none';
89
+
90
+ const bgImage = row.props.bgImage;
91
+ // If the image URL already starts with http:// or https://, use it as is
92
+ if (typeof bgImage === 'string' && (bgImage.startsWith('http://') || bgImage.startsWith('https://'))) {
93
+ return `url(${bgImage})`;
94
+ }
95
+ // Otherwise, prepend the Linode URL
96
+ return `url(${Linodeurl}${bgImage})`;
97
+ };
43
98
 
44
99
  return (
45
100
  <div
46
101
  style={{
47
102
  minHeight: row.props.minHeight,
48
103
  backgroundColor: row.props.bgColor,
49
- backgroundImage: row.props.bgImage ? `url(${row.props.bgImage})` : 'none',
104
+ backgroundImage: getBackgroundImageUrl(),
50
105
  backgroundSize: row.props.bgsize,
51
106
  backgroundPosition: 'center',
52
107
  width: '100%',
@@ -54,15 +109,21 @@ const RowComponent: React.FC<RowComponentProps> = ({
54
109
  border: '1px solid #e0e0e0',
55
110
  borderRadius: '4px',
56
111
  boxSizing: 'border-box',
57
- overflow: 'hidden',
112
+ overflow: overflowStyle,
58
113
  position: 'relative',
59
114
  display: currentMode.isVisible !== false ? 'block' : 'none',
115
+ top: currentMode.top,
116
+ bottom: currentMode.bottom,
60
117
  }}
61
118
  >
62
119
  {/* Row Content */}
63
120
  <div style={{
64
121
  width: '100%',
65
- display: 'block',
122
+ display: useFlexView ? 'flex' : 'block',
123
+ flexDirection: 'row',
124
+ alignItems: useFlexView ? (row.props.align === 'initial' ? 'initial' : getAlignItems(row.props.align || 'flex-start')) : undefined,
125
+ justifyContent: useFlexView ? (row.props.justify === 'initial' ? 'initial' : getJustifyContent(row.props.justify || 'flex-start')) : undefined,
126
+ flexWrap: useFlexView ? (row.props.nowrap === true ? 'nowrap' : 'wrap') : undefined,
66
127
  position: 'relative',
67
128
  padding: '5px',
68
129
  boxSizing: 'border-box'
@@ -81,8 +142,8 @@ const RowComponent: React.FC<RowComponentProps> = ({
81
142
  isSubmitting={isSubmitting}
82
143
  />
83
144
  ))}
84
- {/* Clear float after all children */}
85
- <div style={{ clear: 'both' }} />
145
+ {/* Clear float after all children (only needed when not using flexbox) */}
146
+ {!useFlexView && <div style={{ clear: 'both' }} />}
86
147
  </div>
87
148
  </div>
88
149
  );