From af10193ecc6110843e3d5b121602d97aff885e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Sun, 14 Dec 2025 19:02:35 -0500 Subject: [PATCH 1/5] creation snake_case to camelCase convertor for create and update --- frontend-web-free/src/api/krowSDK.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frontend-web-free/src/api/krowSDK.js b/frontend-web-free/src/api/krowSDK.js index 4f9c2f0b..93a31ed3 100644 --- a/frontend-web-free/src/api/krowSDK.js +++ b/frontend-web-free/src/api/krowSDK.js @@ -358,6 +358,21 @@ const normalizeResultToArray = (res) => { // --- Entities Module ( Data Connect, without REST Base44) --- const entitiesModule = {}; +// --- Helper to convert snake_case to camelCase recursively --- +const toCamel = (value) => { + if (Array.isArray(value)) { + return value.map(toCamel); + } + if (value && typeof value === "object") { + return Object.entries(value).reduce((acc, [key, val]) => { + const camelKey = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()); + acc[camelKey] = toCamel(val); + return acc; + }, {}); + } + return value; +}; + Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { entitiesModule[entityName] = { @@ -510,6 +525,9 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { payload = params; } + //converting to camelCase for data connect + payload = toCamel(payload); + return fn(dataConnect, payload); }, }), @@ -560,6 +578,9 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { ); } + if (data && typeof data === "object") { + data = toCamel(data); + } const vars = { id, ...data }; return fn(dataConnect, vars); From c8cd750b4f7dc615667424be175ae6b3dd35661b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:32:54 -0500 Subject: [PATCH 2/5] modifiying staff schema for front --- dataconnect/connector/staff/mutations.gql | 6 +++--- dataconnect/schema/staff.gql | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dataconnect/connector/staff/mutations.gql b/dataconnect/connector/staff/mutations.gql index 64f2954a..28c40b21 100644 --- a/dataconnect/connector/staff/mutations.gql +++ b/dataconnect/connector/staff/mutations.gql @@ -10,12 +10,12 @@ mutation CreateStaff( $track: String, $position: String, $profileType: ProfileType, - $employmentType: EmploymentType!, + $employmentType: EmploymentType, $english: EnglishLevel, $rate: Float, $rating: Float, $reliabilityScore: Int, - $backgroundCheckStatus: BackgroundCheckStatus! + $backgroundCheckStatus: BackgroundCheckStatus, $notes: String ) @auth(level: USER) { staff_insert( @@ -60,7 +60,7 @@ mutation UpdateStaff( $rate: Float, $rating: Float, $reliabilityScore: Int, - $backgroundCheckStatus: BackgroundCheckStatus + $backgroundCheckStatus: BackgroundCheckStatus, $notes: String ) @auth(level: USER) { staff_update( diff --git a/dataconnect/schema/staff.gql b/dataconnect/schema/staff.gql index a4aaf878..9a566a52 100644 --- a/dataconnect/schema/staff.gql +++ b/dataconnect/schema/staff.gql @@ -53,12 +53,12 @@ type Staff @table(name: "staffs") { track: String position: String profileType: ProfileType @col(name: "profile_type") - employmentType: EmploymentType! @col(name: "employment_type") + employmentType: EmploymentType @col(name: "employment_type") english: EnglishLevel rate: Float rating: Float reliabilityScore: Int @col(name: "reliability_score") - backgroundCheckStatus: BackgroundCheckStatus! @col(name: "background_check_status") + backgroundCheckStatus: BackgroundCheckStatus @col(name: "background_check_status") notes: String createdDate: Timestamp @default(expr: "request.time") updatedDate: Timestamp @default(expr: "request.time") From 6399b5f25aef95052058c11ee4da6ba5d67e2a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:21:11 -0500 Subject: [PATCH 3/5] chaging vendor_id to string --- dataconnect/connector/staff/mutations.gql | 4 ++-- dataconnect/connector/staff/queries.gql | 2 +- dataconnect/schema/staff.gql | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dataconnect/connector/staff/mutations.gql b/dataconnect/connector/staff/mutations.gql index 28c40b21..4523b114 100644 --- a/dataconnect/connector/staff/mutations.gql +++ b/dataconnect/connector/staff/mutations.gql @@ -1,6 +1,6 @@ mutation CreateStaff( $employeeName: String!, - $vendorId: UUID, + $vendorId: String, $vendorName: String, $manager: String, $contactNumber: String, @@ -45,7 +45,7 @@ mutation CreateStaff( mutation UpdateStaff( $id: UUID!, $employeeName: String, - $vendorId: UUID, + $vendorId: String, $vendorName: String, $manager: String, $contactNumber: String, diff --git a/dataconnect/connector/staff/queries.gql b/dataconnect/connector/staff/queries.gql index 87ed5235..4574e21f 100644 --- a/dataconnect/connector/staff/queries.gql +++ b/dataconnect/connector/staff/queries.gql @@ -50,7 +50,7 @@ query getStaffById( query filterStaff( $employeeName: String, - $vendorId: UUID, + $vendorId: String, $department: StaffDepartment, $employmentType: EmploymentType, $english: EnglishLevel, diff --git a/dataconnect/schema/staff.gql b/dataconnect/schema/staff.gql index 9a566a52..f49f3473 100644 --- a/dataconnect/schema/staff.gql +++ b/dataconnect/schema/staff.gql @@ -43,7 +43,7 @@ enum BackgroundCheckStatus { type Staff @table(name: "staffs") { id: UUID! @default(expr: "uuidV4()") employeeName: String! @col(name: "employee_name") - vendorId: UUID @col(name: "vendor_id") # vendor_id (FK lógica a Vendor.id) + vendorId: String @col(name: "vendor_id") # vendor_id (FK lógica a Vendor.id) vendorName: String @col(name: "vendor_name") manager: String contactNumber: String @col(name: "contact_number") From e7546715b2664bd54ed18d15629d6055f1b92c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:22:06 -0500 Subject: [PATCH 4/5] updating important things for the functionality of the front --- frontend-web-free/src/api/krowSDK.js | 197 ++++++++++++++------------- 1 file changed, 100 insertions(+), 97 deletions(-) diff --git a/frontend-web-free/src/api/krowSDK.js b/frontend-web-free/src/api/krowSDK.js index 93a31ed3..454db78a 100644 --- a/frontend-web-free/src/api/krowSDK.js +++ b/frontend-web-free/src/api/krowSDK.js @@ -373,6 +373,24 @@ const toCamel = (value) => { return value; }; +// --- Helper to convert camelCase to snake_case recursively --- +const toSnake = (value) => { + if (Array.isArray(value)) { + return value.map(toSnake); + } + if (value && typeof value === "object") { + return Object.entries(value).reduce((acc, [key, val]) => { + const snakeKey = key + .replace(/([A-Z])/g, "_$1") + .toLowerCase(); + acc[snakeKey] = toSnake(val); + return acc; + }, {}); + } + return value; +}; + + Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { entitiesModule[entityName] = { @@ -392,102 +410,91 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { `Data Connect operation "${ops.list}" not found for entity "${entityName}".` ); } - - //return fn(dataConnect); - /*let variables; - const maybeVars = params[0]; - - if (maybeVars && typeof maybeVars === 'object' && !Array.isArray(maybeVars)) { - variables = maybeVars; + + let sort; + let limit; + let baseVariables; // por si algún list usa variables (como Team) + + if (args.length === 1) { + const [a0] = args; + if (typeof a0 === "string") { + // list('-created_date') + sort = a0; + } else if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { + // list({ ...vars }) -> reservado para queries que acepten variables + baseVariables = a0; + } + } else if (args.length === 2) { + const [a0, a1] = args; + if (typeof a0 === "string" && typeof a1 === "number") { + // list('-created_date', 50) + sort = a0; + limit = a1; + } else if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { + // list({ ...vars }, '-created_date') + baseVariables = a0; + if (typeof a1 === "string") sort = a1; + } + } else if (args.length >= 3) { + const [a0, a1, a2] = args; + if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { + // list({ ...vars }, '-created_date', 50) + baseVariables = a0; + if (typeof a1 === "string") sort = a1; + if (typeof a2 === "number") limit = a2; + } + } + + // COMMENT FIX: variables que realmente se mandan a DataConnect + let variables = baseVariables; + + // COMMENT FIX: caso especial para Team, que SÍ tiene orderBy/limit en el query + if (entityName === "Team") { + variables = variables || {}; + if (sort) { + const desc = sort.startsWith("-"); + variables.orderByCreatedDate = desc ? "DESC" : "ASC"; + } + if (typeof limit === "number") { + variables.limit = limit; + } } const res = await fn(dataConnect, variables); - return normalizeResultToArray(res); - */ + let items = normalizeResultToArray(res); - let sort; - let limit; - let baseVariables; // por si algún list usa variables (como Team) + // COMMENT FIX: para entidades que NO tienen orderBy/limit en el query, + // aplicamos sort/limit en el front como fallback. + if (entityName !== "Team" && sort) { + const desc = sort.startsWith("-"); + const field = desc ? sort.slice(1) : sort; // '-created_date' -> 'created_date' - if (args.length === 1) { - const [a0] = args; - if (typeof a0 === "string") { - // list('-created_date') - sort = a0; - } else if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { - // list({ ...vars }) -> reservado para queries que acepten variables - baseVariables = a0; - } - } else if (args.length === 2) { - const [a0, a1] = args; - if (typeof a0 === "string" && typeof a1 === "number") { - // list('-created_date', 50) - sort = a0; - limit = a1; - } else if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { - // list({ ...vars }, '-created_date') - baseVariables = a0; - if (typeof a1 === "string") sort = a1; - } - } else if (args.length >= 3) { - const [a0, a1, a2] = args; - if (a0 && typeof a0 === "object" && !Array.isArray(a0)) { - // list({ ...vars }, '-created_date', 50) - baseVariables = a0; - if (typeof a1 === "string") sort = a1; - if (typeof a2 === "number") limit = a2; - } - } + items = items.slice().sort((a, b) => { + const av = a?.[field]; + const bv = b?.[field]; - // COMMENT FIX: variables que realmente se mandan a DataConnect - let variables = baseVariables; + if (av == null && bv == null) return 0; + if (av == null) return 1; + if (bv == null) return -1; - // COMMENT FIX: caso especial para Team, que SÍ tiene orderBy/limit en el query - if (entityName === "Team") { - variables = variables || {}; - if (sort) { - const desc = sort.startsWith("-"); - variables.orderByCreatedDate = desc ? "DESC" : "ASC"; - } - if (typeof limit === "number") { - variables.limit = limit; - } - } + const da = new Date(av); + const db = new Date(bv); + if (!isNaN(da) && !isNaN(db)) { + return desc ? db - da : da - db; + } - const res = await fn(dataConnect, variables); - let items = normalizeResultToArray(res); - - // COMMENT FIX: para entidades que NO tienen orderBy/limit en el query, - // aplicamos sort/limit en el front como fallback. - if (entityName !== "Team" && sort) { - const desc = sort.startsWith("-"); - const field = desc ? sort.slice(1) : sort; // '-created_date' -> 'created_date' - - items = items.slice().sort((a, b) => { - const av = a?.[field]; - const bv = b?.[field]; - - if (av == null && bv == null) return 0; - if (av == null) return 1; - if (bv == null) return -1; - - const da = new Date(av); - const db = new Date(bv); - if (!isNaN(da) && !isNaN(db)) { - return desc ? db - da : da - db; + if (av < bv) return desc ? 1 : -1; + if (av > bv) return desc ? -1 : 1; + return 0; + }); } - if (av < bv) return desc ? 1 : -1; - if (av > bv) return desc ? -1 : 1; - return 0; - }); - } - - if (entityName !== "Team" && typeof limit === "number") { - items = items.slice(0, limit); - } - - return items; + if (entityName !== "Team" && typeof limit === "number") { + items = items.slice(0, limit); + } + //console.log(items) + //return items; + return items.map(toSnake); }, }), @@ -501,14 +508,6 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { ); } - /*const { data } = params ?? {}; - if (!data) { - throw new Error( - `${entityName}.create expects a payload like { data: { ...fields } }` - ); - } - - return fn(dataConnect, data);*/ if (!params || typeof params !== 'object') { throw new Error( `${entityName}.create expects an object with the fields to insert` @@ -546,13 +545,16 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { throw new Error(`${entityName}.get expects an object of variables (e.g. { id })`); } - return fn(dataConnect, params); + //return fn(dataConnect, params); + const result = await fn(dataConnect, params); + return toSnake(result); + }, }), //update ...(ops.update && { - update: async (params) => { + update: async (id,params) => { const fn = dcSdk[ops.update]; if (typeof fn !== 'function') { throw new Error( @@ -566,7 +568,8 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { ); } - const { id, data } = params; + //const { id, data } = params; + let data = params; if (!id) { throw new Error(`${entityName}.update requires an "id" field`); From ea3fe79c8e3dadb4d0b55a7fe4820cd666b56730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:26:22 -0500 Subject: [PATCH 5/5] modification just for test staff crud --- .../src/components/staff/StaffForm.jsx | 154 +++++++++--------- frontend-web-free/src/pages/EditStaff.jsx | 4 + 2 files changed, 81 insertions(+), 77 deletions(-) diff --git a/frontend-web-free/src/components/staff/StaffForm.jsx b/frontend-web-free/src/components/staff/StaffForm.jsx index 26c0608f..1cd086a5 100644 --- a/frontend-web-free/src/components/staff/StaffForm.jsx +++ b/frontend-web-free/src/components/staff/StaffForm.jsx @@ -14,35 +14,35 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { employee_name: "", manager: "", contact_number: "", - phone: "", + //phone: "", email: "", // Added email field department: "", hub_location: "", - event_location: "", + //event_location: "", track: "", - address: "", - city: "", + //address: "", + //city: "", position: "", - position_2: "", - initial: "", + //position_2: "", + //initial: "", profile_type: "", employment_type: "", english: "", - english_required: false, - check_in: "", - replaced_by: "", - ro: "", - mon: "", - schedule_days: "", - invoiced: false, - action: "", + //english_required: false, + //check_in: "", + //replaced_by: "", + //ro: "", + //mon: "", + //schedule_days: "", + //invoiced: false, + //action: "", notes: "", - accounting_comments: "", + //accounting_comments: "", rating: 0, - shift_coverage_percentage: 100, - cancellation_count: 0, - no_show_count: 0, // Added no_show_count field - total_shifts: 0, + //shift_coverage_percentage: 100, + //cancellation_count: 0, + //no_show_count: 0, // Added no_show_count field + //total_shifts: 0, reliability_score: 100 }); @@ -81,7 +81,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { /> -