Skip to content

Commit be31a39

Browse files
committed
Fixing 0 allowed for required field. De dupe
1 parent 35897ac commit be31a39

4 files changed

Lines changed: 276 additions & 286 deletions

File tree

apps/api-manager/src/routes/(protected)/dynamic-entities/personal/[entityName]/+page.svelte

Lines changed: 44 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
extractErrorFromResponse,
55
formatErrorForDisplay,
66
} from "$lib/utils/errorHandler";
7+
import {
8+
validateDynamicEntityFields,
9+
convertDynamicEntityFormData,
10+
initialDynamicEntityFormData,
11+
dynamicEntityInputType,
12+
type DynamicEntityFieldDef,
13+
} from "@obp/shared/obp";
714
815
let { data }: { data: PageData } = $props();
916
@@ -16,17 +23,9 @@
1623
let schema = $derived(getSchema(entity));
1724
let entityName = $derived(entity.entity_name || "Unknown");
1825
19-
interface FieldDef {
20-
type?: string;
21-
description?: string;
22-
example?: unknown;
23-
minimum?: number;
24-
maximum?: number;
25-
minLength?: number;
26-
maxLength?: number;
27-
}
28-
29-
let properties = $derived<Record<string, FieldDef>>(schema?.properties || {});
26+
let properties = $derived<Record<string, DynamicEntityFieldDef>>(
27+
schema?.properties || {},
28+
);
3029
let requiredFields = $derived<string[]>(schema?.required || []);
3130
let description = $derived(schema?.description || "No description available");
3231
@@ -118,11 +117,10 @@
118117
let schemaCollapsed = $state(true);
119118
120119
function initializeFormData(record?: any) {
121-
formData = {};
122-
const recordData = record ? getRecordData(record) : null;
123-
Object.keys(properties).forEach((fieldName) => {
124-
formData[fieldName] = recordData ? recordData[fieldName] : "";
125-
});
120+
formData = initialDynamicEntityFormData(
121+
properties,
122+
record ? getRecordData(record) : null,
123+
);
126124
validationErrors = {};
127125
}
128126
@@ -151,110 +149,13 @@
151149
validationErrors = {};
152150
}
153151
154-
function validateField(fieldName: string, value: any): string | null {
155-
const fieldDef = properties[fieldName];
156-
const isRequired = requiredFields.includes(fieldName);
157-
158-
if (isRequired && (!value || value === "")) {
159-
return "This field is required";
160-
}
161-
162-
if (value !== null && value !== undefined && value !== "") {
163-
switch (fieldDef.type) {
164-
case "integer":
165-
case "number":
166-
const num = Number(value);
167-
if (isNaN(num)) {
168-
return "Must be a valid number";
169-
}
170-
if (fieldDef.type === "integer" && !Number.isInteger(num)) {
171-
return "Must be an integer";
172-
}
173-
if (fieldDef.minimum !== undefined && num < fieldDef.minimum) {
174-
return `Must be at least ${fieldDef.minimum}`;
175-
}
176-
if (fieldDef.maximum !== undefined && num > fieldDef.maximum) {
177-
return `Must be at most ${fieldDef.maximum}`;
178-
}
179-
break;
180-
case "boolean":
181-
break;
182-
case "DATE_WITH_DAY":
183-
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
184-
return "Must be in format YYYY-MM-DD";
185-
}
186-
break;
187-
default:
188-
if (fieldDef.minLength && String(value).length < fieldDef.minLength) {
189-
return `Must be at least ${fieldDef.minLength} characters`;
190-
}
191-
if (fieldDef.maxLength && String(value).length > fieldDef.maxLength) {
192-
return `Must be at most ${fieldDef.maxLength} characters`;
193-
}
194-
break;
195-
}
196-
}
197-
198-
return null;
199-
}
200-
201152
function validateAllFields(): boolean {
202-
let isValid = true;
203-
validationErrors = {};
204-
205-
Object.keys(properties).forEach((fieldName) => {
206-
const error = validateField(fieldName, formData[fieldName]);
207-
if (error) {
208-
validationErrors[fieldName] = error;
209-
isValid = false;
210-
}
211-
});
212-
213-
return isValid;
214-
}
215-
216-
function convertFormDataToApiFormat(
217-
data: Record<string, any>,
218-
): Record<string, any> {
219-
const converted: Record<string, any> = {};
220-
221-
Object.keys(properties).forEach((fieldName) => {
222-
const fieldDef = properties[fieldName];
223-
const value = data[fieldName];
224-
225-
if (value === "" || value === null || value === undefined) {
226-
return;
227-
}
228-
229-
switch (fieldDef.type) {
230-
case "boolean":
231-
converted[fieldName] = value ? "true" : "false";
232-
break;
233-
case "integer":
234-
converted[fieldName] = Math.round(Number(value));
235-
break;
236-
case "number":
237-
converted[fieldName] = Number(value);
238-
break;
239-
default:
240-
converted[fieldName] = String(value);
241-
break;
242-
}
243-
});
244-
245-
return converted;
246-
}
247-
248-
function renderFieldInput(fieldName: string, fieldDef: any) {
249-
switch (fieldDef.type) {
250-
case "boolean":
251-
return "checkbox";
252-
case "integer":
253-
case "number":
254-
return "number";
255-
default:
256-
return "text";
257-
}
153+
validationErrors = validateDynamicEntityFields(
154+
properties,
155+
requiredFields,
156+
formData,
157+
);
158+
return Object.keys(validationErrors).length === 0;
258159
}
259160
260161
// Extract records from response (client-side refetch)
@@ -296,7 +197,7 @@
296197
isSubmitting = true;
297198
298199
try {
299-
const convertedData = convertFormDataToApiFormat(formData);
200+
const convertedData = convertDynamicEntityFormData(properties, formData);
300201
301202
const response = await fetch(
302203
`/proxy/obp/dynamic-entity/my/${entityName}`,
@@ -346,7 +247,7 @@
346247
isSubmitting = true;
347248
348249
try {
349-
const convertedData = convertFormDataToApiFormat(formData);
250+
const convertedData = convertDynamicEntityFormData(properties, formData);
350251
351252
const response = await fetch(
352253
`/proxy/obp/dynamic-entity/my/${entityName}/${recordId}`,
@@ -954,7 +855,7 @@
954855
<div class="space-y-4">
955856
{#each Object.entries(properties) as [fieldName, fieldDef]}
956857
{@const isRequired = requiredFields.includes(fieldName)}
957-
{@const inputType = renderFieldInput(fieldName, fieldDef)}
858+
{@const inputType = dynamicEntityInputType(fieldDef)}
958859
<div>
959860
<label
960861
for="create-{fieldName}"
@@ -984,6 +885,16 @@
984885
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
985886
/>
986887
</div>
888+
{:else if inputType === "textarea"}
889+
<textarea
890+
id="create-{fieldName}"
891+
bind:value={formData[fieldName]}
892+
rows="8"
893+
placeholder={fieldDef.example
894+
? JSON.stringify(fieldDef.example, null, 2)
895+
: '{ }'}
896+
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 font-mono text-sm 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"
897+
></textarea>
987898
{:else}
988899
<input
989900
type={inputType}
@@ -1086,7 +997,7 @@
1086997
<div class="space-y-4">
1087998
{#each Object.entries(properties) as [fieldName, fieldDef]}
1088999
{@const isRequired = requiredFields.includes(fieldName)}
1089-
{@const inputType = renderFieldInput(fieldName, fieldDef)}
1000+
{@const inputType = dynamicEntityInputType(fieldDef)}
10901001
<div>
10911002
<label
10921003
for="edit-{fieldName}"
@@ -1116,6 +1027,16 @@
11161027
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
11171028
/>
11181029
</div>
1030+
{:else if inputType === "textarea"}
1031+
<textarea
1032+
id="edit-{fieldName}"
1033+
bind:value={formData[fieldName]}
1034+
rows="8"
1035+
placeholder={fieldDef.example
1036+
? JSON.stringify(fieldDef.example, null, 2)
1037+
: '{ }'}
1038+
class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 font-mono text-sm 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"
1039+
></textarea>
11191040
{:else}
11201041
<input
11211042
type={inputType}

0 commit comments

Comments
 (0)