Skip to content

Commit 5787b86

Browse files
committed
number handling WIP
1 parent 71708b1 commit 5787b86

File tree

2 files changed

+190
-29
lines changed

2 files changed

+190
-29
lines changed

src/routes/(protected)/dynamic-entities/system/[id]/crud/+page.svelte

Lines changed: 153 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,23 @@
9595
return "This field is required";
9696
}
9797
98-
if (value && value !== "") {
98+
if (value !== null && value !== undefined && value !== "") {
9999
switch (fieldDef.type) {
100100
case "integer":
101-
if (!/^-?\d+$/.test(value.toString())) {
102-
return "Must be a valid integer";
103-
}
104-
break;
105101
case "number":
106-
if (isNaN(Number(value))) {
102+
const num = Number(value);
103+
if (isNaN(num)) {
107104
return "Must be a valid number";
108105
}
106+
if (fieldDef.type === "integer" && !Number.isInteger(num)) {
107+
return "Must be an integer";
108+
}
109+
if (fieldDef.minimum !== undefined && num < fieldDef.minimum) {
110+
return `Must be at least ${fieldDef.minimum}`;
111+
}
112+
if (fieldDef.maximum !== undefined && num > fieldDef.maximum) {
113+
return `Must be at most ${fieldDef.maximum}`;
114+
}
109115
break;
110116
case "boolean":
111117
// Accept true/false or convert from string
@@ -115,13 +121,15 @@
115121
return "Must be in format YYYY-MM-DD";
116122
}
117123
break;
118-
}
119-
120-
if (fieldDef.minLength && value.length < fieldDef.minLength) {
121-
return `Must be at least ${fieldDef.minLength} characters`;
122-
}
123-
if (fieldDef.maxLength && value.length > fieldDef.maxLength) {
124-
return `Must be at most ${fieldDef.maxLength} characters`;
124+
default:
125+
// String validation
126+
if (fieldDef.minLength && String(value).length < fieldDef.minLength) {
127+
return `Must be at least ${fieldDef.minLength} characters`;
128+
}
129+
if (fieldDef.maxLength && String(value).length > fieldDef.maxLength) {
130+
return `Must be at most ${fieldDef.maxLength} characters`;
131+
}
132+
break;
125133
}
126134
}
127135
@@ -143,6 +151,44 @@
143151
return isValid;
144152
}
145153
154+
function convertFormDataToApiFormat(
155+
data: Record<string, any>,
156+
): Record<string, any> {
157+
const converted: Record<string, any> = {};
158+
159+
Object.keys(properties).forEach((fieldName) => {
160+
const fieldDef = properties[fieldName];
161+
const value = data[fieldName];
162+
163+
// Skip empty values
164+
if (value === "" || value === null || value === undefined) {
165+
return;
166+
}
167+
168+
switch (fieldDef.type) {
169+
case "boolean":
170+
// Convert boolean to string "true" or "false"
171+
converted[fieldName] = value ? "true" : "false";
172+
break;
173+
case "integer":
174+
// Convert to integer number
175+
const intValue = Number(value);
176+
converted[fieldName] = Math.round(intValue);
177+
break;
178+
case "number":
179+
// Convert to number (JavaScript/JSON doesn't distinguish int vs float)
180+
converted[fieldName] = Number(value);
181+
break;
182+
default:
183+
// Keep as string
184+
converted[fieldName] = String(value);
185+
break;
186+
}
187+
});
188+
189+
return converted;
190+
}
191+
146192
async function handleCreate() {
147193
if (!validateAllFields()) {
148194
alert("Please fix validation errors");
@@ -152,28 +198,48 @@
152198
isSubmitting = true;
153199
154200
try {
201+
const convertedData = convertFormDataToApiFormat(formData);
202+
console.log("Original formData:", formData);
203+
console.log("Converted data being sent:", convertedData);
204+
console.log(
205+
"Converted data JSON:",
206+
JSON.stringify(convertedData, null, 2),
207+
);
208+
155209
const response = await fetch(
156210
`/api/dynamic-entities/${entity.dynamicEntityId}/data`,
157211
{
158212
method: "POST",
159213
headers: {
160214
"Content-Type": "application/json",
161215
},
162-
body: JSON.stringify(formData),
216+
credentials: "include",
217+
body: JSON.stringify(convertedData),
163218
},
164219
);
165220
166221
if (!response.ok) {
167-
const error = await response.json();
168-
throw new Error(error.message || "Failed to create record");
222+
let errorMessage = "Failed to create record";
223+
try {
224+
const error = await response.json();
225+
errorMessage = error.error || error.message || errorMessage;
226+
console.error("API Error Response:", error);
227+
} catch (e) {
228+
const text = await response.text();
229+
console.error("Non-JSON Error Response:", text);
230+
errorMessage = `Server error: ${response.status} ${response.statusText}`;
231+
}
232+
throw new Error(errorMessage);
169233
}
170234
171235
const result = await response.json();
172236
dataRecords = [...dataRecords, result];
173237
alert("Record created successfully");
174238
closeModals();
175239
} catch (error) {
176-
alert(error instanceof Error ? error.message : "Failed to create record");
240+
const errorMsg =
241+
error instanceof Error ? error.message : "Failed to create record";
242+
alert(`Error: ${errorMsg}`);
177243
console.error("Create error:", error);
178244
} finally {
179245
isSubmitting = false;
@@ -194,20 +260,32 @@
194260
isSubmitting = true;
195261
196262
try {
263+
const convertedData = convertFormDataToApiFormat(formData);
264+
197265
const response = await fetch(
198266
`/api/dynamic-entities/${entity.dynamicEntityId}/data/${selectedRecord.id}`,
199267
{
200268
method: "PUT",
201269
headers: {
202270
"Content-Type": "application/json",
203271
},
204-
body: JSON.stringify(formData),
272+
credentials: "include",
273+
body: JSON.stringify(convertedData),
205274
},
206275
);
207276
208277
if (!response.ok) {
209-
const error = await response.json();
210-
throw new Error(error.message || "Failed to update record");
278+
let errorMessage = "Failed to update record";
279+
try {
280+
const error = await response.json();
281+
errorMessage = error.error || error.message || errorMessage;
282+
console.error("API Error Response:", error);
283+
} catch (e) {
284+
const text = await response.text();
285+
console.error("Non-JSON Error Response:", text);
286+
errorMessage = `Server error: ${response.status} ${response.statusText}`;
287+
}
288+
throw new Error(errorMessage);
211289
}
212290
213291
const result = await response.json();
@@ -217,7 +295,9 @@
217295
alert("Record updated successfully");
218296
closeModals();
219297
} catch (error) {
220-
alert(error instanceof Error ? error.message : "Failed to update record");
298+
const errorMsg =
299+
error instanceof Error ? error.message : "Failed to update record";
300+
alert(`Error: ${errorMsg}`);
221301
console.error("Update error:", error);
222302
} finally {
223303
isSubmitting = false;
@@ -234,6 +314,7 @@
234314
`/api/dynamic-entities/${entity.dynamicEntityId}/data/${record.id}`,
235315
{
236316
method: "DELETE",
317+
credentials: "include",
237318
},
238319
);
239320
@@ -260,7 +341,7 @@
260341
case "number":
261342
return "number";
262343
case "DATE_WITH_DAY":
263-
return "date";
344+
return "text";
264345
default:
265346
return "text";
266347
}
@@ -605,6 +686,11 @@
605686
{fieldDef.description}
606687
</p>
607688
{/if}
689+
{#if fieldDef.type === "DATE_WITH_DAY"}
690+
<p class="mt-1 text-xs text-blue-600 dark:text-blue-400">
691+
Format: YYYY-MM-DD (e.g., 2023-06-15)
692+
</p>
693+
{/if}
608694
{#if inputType === "checkbox"}
609695
<div class="mt-2">
610696
<input
@@ -619,8 +705,26 @@
619705
type={inputType}
620706
id="create-{fieldName}"
621707
bind:value={formData[fieldName]}
622-
placeholder={fieldDef.example ? String(fieldDef.example) : ""}
623-
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-gray-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
708+
placeholder={fieldDef.type === "DATE_WITH_DAY"
709+
? "YYYY-MM-DD"
710+
: fieldDef.example
711+
? String(fieldDef.example)
712+
: ""}
713+
pattern={fieldDef.type === "DATE_WITH_DAY"
714+
? "\\d{4}-\\d{2}-\\d{2}"
715+
: undefined}
716+
step={fieldDef.type === "integer"
717+
? "1"
718+
: fieldDef.type === "number"
719+
? "any"
720+
: undefined}
721+
min={fieldDef.minimum !== undefined
722+
? fieldDef.minimum
723+
: undefined}
724+
max={fieldDef.maximum !== undefined
725+
? fieldDef.maximum
726+
: undefined}
727+
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 font-mono text-gray-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
624728
/>
625729
{/if}
626730
{#if validationErrors[fieldName]}
@@ -715,6 +819,11 @@
715819
{fieldDef.description}
716820
</p>
717821
{/if}
822+
{#if fieldDef.type === "DATE_WITH_DAY"}
823+
<p class="mt-1 text-xs text-blue-600 dark:text-blue-400">
824+
Format: YYYY-MM-DD (e.g., 2023-06-15)
825+
</p>
826+
{/if}
718827
{#if inputType === "checkbox"}
719828
<div class="mt-2">
720829
<input
@@ -729,8 +838,26 @@
729838
type={inputType}
730839
id="edit-{fieldName}"
731840
bind:value={formData[fieldName]}
732-
placeholder={fieldDef.example ? String(fieldDef.example) : ""}
733-
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-gray-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
841+
placeholder={fieldDef.type === "DATE_WITH_DAY"
842+
? "YYYY-MM-DD"
843+
: fieldDef.example
844+
? String(fieldDef.example)
845+
: ""}
846+
pattern={fieldDef.type === "DATE_WITH_DAY"
847+
? "\\d{4}-\\d{2}-\\d{2}"
848+
: undefined}
849+
step={fieldDef.type === "integer"
850+
? "1"
851+
: fieldDef.type === "number"
852+
? "any"
853+
: undefined}
854+
min={fieldDef.minimum !== undefined
855+
? fieldDef.minimum
856+
: undefined}
857+
max={fieldDef.maximum !== undefined
858+
? fieldDef.maximum
859+
: undefined}
860+
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 font-mono text-gray-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
734861
/>
735862
{/if}
736863
{#if validationErrors[fieldName]}

src/routes/api/dynamic-entities/[id]/data/+server.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,27 @@ export const GET: RequestHandler = async ({ params, locals }) => {
9393

9494
// POST - Create a new record
9595
export const POST: RequestHandler = async ({ params, request, locals }) => {
96+
logger.info("=== POST Create Record Request ===");
97+
logger.info("Params:", params);
98+
9699
const session = locals.session;
100+
logger.info("Session exists:", !!session);
101+
logger.info("Session has data:", !!session?.data);
102+
logger.info("Session has user:", !!session?.data?.user);
97103

98104
if (!session?.data?.user) {
99-
return json({ error: "Unauthorized" }, { status: 401 });
105+
logger.error("Unauthorized: No session or user data");
106+
return json({ error: "Unauthorized - No session" }, { status: 401 });
100107
}
101108

102109
const sessionOAuth = SessionOAuthHelper.getSessionOAuth(session);
110+
logger.info("SessionOAuth retrieved:", !!sessionOAuth);
111+
103112
const accessToken = sessionOAuth?.accessToken;
113+
logger.info("Access token available:", !!accessToken);
104114

105115
if (!accessToken) {
106-
logger.warn("No access token available");
116+
logger.error("No access token available in session");
107117
return json({ error: "No API access token available" }, { status: 401 });
108118
}
109119

@@ -115,27 +125,51 @@ export const POST: RequestHandler = async ({ params, request, locals }) => {
115125
}
116126

117127
const body = await request.json();
128+
logger.info("Request body received:", JSON.stringify(body, null, 2));
118129

119130
if (!body || typeof body !== "object") {
131+
logger.error("Invalid request body");
120132
return json(
121133
{ error: "Request body must be a valid object" },
122134
{ status: 400 },
123135
);
124136
}
125137

126138
// Get entity name from ID
139+
logger.info(`Looking up entity name for ID: ${id}`);
127140
const entityName = await getEntityName(id, accessToken);
141+
logger.info(`Entity name resolved: ${entityName}`);
142+
128143
if (!entityName) {
144+
logger.error(`Entity not found for ID: ${id}`);
129145
return json({ error: "Entity not found" }, { status: 404 });
130146
}
131147

132148
logger.info(`Creating record for entity: ${entityName}`);
133-
logger.info(`Data: ${JSON.stringify(body)}`);
149+
logger.info(`Request data: ${JSON.stringify(body)}`);
150+
151+
// Log detailed type information
152+
Object.keys(body).forEach((key) => {
153+
const value = body[key];
154+
const type = typeof value;
155+
logger.info(
156+
`Field '${key}': value='${value}', type='${type}', isNumber=${typeof value === "number"}, isInteger=${Number.isInteger(value)}`,
157+
);
158+
});
134159

135160
const endpoint = `/obp/dynamic-entity/${entityName}`;
161+
logger.info(`Calling OBP endpoint: POST ${endpoint}`);
162+
logger.info(`Request body being sent to OBP: ${JSON.stringify(body)}`);
163+
logger.info(
164+
`Stringified body type check:`,
165+
typeof body,
166+
Array.isArray(body),
167+
);
168+
136169
const response = await obp_requests.post(endpoint, body, accessToken);
137170

138171
logger.info("Record created successfully");
172+
logger.info("Response:", JSON.stringify(response));
139173
return json(response);
140174
} catch (err) {
141175
logger.error("Error creating record:", err);

0 commit comments

Comments
 (0)