diff --git a/dataconnect/connector/staff/mutations.gql b/dataconnect/connector/staff/mutations.gql index 64f2954a..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, @@ -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( @@ -45,7 +45,7 @@ mutation CreateStaff( mutation UpdateStaff( $id: UUID!, $employeeName: String, - $vendorId: UUID, + $vendorId: String, $vendorName: String, $manager: String, $contactNumber: String, @@ -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/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 a4aaf878..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") @@ -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") diff --git a/frontend-web-free/src/api/krowSDK.js b/frontend-web-free/src/api/krowSDK.js index 4f9c2f0b..454db78a 100644 --- a/frontend-web-free/src/api/krowSDK.js +++ b/frontend-web-free/src/api/krowSDK.js @@ -358,6 +358,39 @@ 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; +}; + +// --- 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] = { @@ -377,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); }, }), @@ -486,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` @@ -510,6 +524,9 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { payload = params; } + //converting to camelCase for data connect + payload = toCamel(payload); + return fn(dataConnect, payload); }, }), @@ -528,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( @@ -548,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`); @@ -560,6 +581,9 @@ Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => { ); } + if (data && typeof data === "object") { + data = toCamel(data); + } const vars = { id, ...data }; return fn(dataConnect, vars); 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 }) { /> -
+ {/*
-
+
*/}
@@ -103,7 +103,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { />
-
+ {/*
-
+
*/}
@@ -121,9 +121,9 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { - Skilled - Beginner - Cross-Trained + Skilled + Beginner + Cross-Trained
@@ -135,13 +135,13 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { - Full Time - Part Time - On call - Weekends - Specific Days - Seasonal - Medical Leave + Full Time + Part Time + On call + Weekends + Specific Days + Seasonal + Medical Leave @@ -187,7 +187,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { /> -
+ {/*
handleChange('phone', e.target.value)} className="border-slate-200" /> -
+
*/} @@ -234,7 +234,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { /> -
+ {/*
handleChange('shift_coverage_percentage', parseInt(e.target.value) || 0)} className="border-slate-200" /> -
+
*/} -
+ {/*
handleChange('cancellation_count', parseInt(e.target.value) || 0)} className="border-slate-200" /> -
+
*/} {/* New No Show Count field */} -
+ {/*
handleChange('no_show_count', parseInt(e.target.value) || 0)} className="border-slate-200" /> -
+
*/} {/* End new No Show Count field */} -
+ {/*
handleChange('total_shifts', parseInt(e.target.value) || 0)} className="border-slate-200" /> -
+
*/} -
+ {/*
-
+
*/} @@ -314,19 +314,19 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { - Operations - Sales + Operations + Sales HR - Finance + Finance IT - Marketing - Customer Service - Logistics + Marketing + Customer Service + Logistics -
+ {/*
-
+
*/}
@@ -347,7 +347,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { />
-
+ {/*
handleChange('event_location', e.target.value)} className="border-slate-200" /> -
+
*/}
@@ -367,7 +367,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }) { />
-
+ {/*