validating data
This commit is contained in:
@@ -1,253 +0,0 @@
|
||||
# DataConnect – Inconsistencies between the Base44 frontend and the backend (Firebase Data Connect + PostgreSQL)
|
||||
**Author:** José Salazar
|
||||
**Date:** Dec 2025
|
||||
|
||||
---
|
||||
|
||||
## 📌 Purpose of this document
|
||||
|
||||
Document all findings during the integration of the new backend
|
||||
(**Firebase Data Connect + PostgreSQL**) with the frontend generated by **Base44 AI**.
|
||||
|
||||
This document summarizes:
|
||||
|
||||
- Issues found
|
||||
- camelCase vs snake_case inconsistencies
|
||||
- Enum inconsistencies (uppercase/lowercase and dashes)
|
||||
- Differences between what DataConnect returns vs what the frontend expects
|
||||
- Recommended fixes
|
||||
- Suggestions for Base44 AI to update its model
|
||||
- Impact on queries, mutations, and the generated SDK
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ Enums – Different formats between Front and Backend
|
||||
|
||||
### Observation
|
||||
|
||||
In the frontend, enum values are in mixed formats, for example:
|
||||
|
||||
- UPPERCASE: SKILLED
|
||||
- camelCase: fullTime
|
||||
|
||||
In the backend (DataConnect schema), enums are defined only in UPPERCASE, for example:
|
||||
|
||||
- FULL_TIME
|
||||
- CROSS_TRAINED
|
||||
- NOT_REQUIRED
|
||||
- PENDING
|
||||
|
||||
DataConnect only accepts these exact values.
|
||||
|
||||
### Problem
|
||||
|
||||
When the frontend sends:
|
||||
|
||||
- "crossTrained" instead of CROSS_TRAINED
|
||||
- "fluent" instead of FLUENT
|
||||
|
||||
### Impact
|
||||
|
||||
- Mutations can fail or return enum validation errors.
|
||||
- Filters using enums return no results.
|
||||
- Behavior changes depending on how Base44 AI generated the object.
|
||||
|
||||
### Recommendation
|
||||
|
||||
- Define a single standard: **ALL enums must be UPPERCASE** on the frontend and backend.
|
||||
- Before sending to the backend, normalize enum values to uppercase.
|
||||
|
||||
### Suggestion for Base44 AI
|
||||
|
||||
- Adjust models so they always generate enums in UPPERCASE.
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ Enums with dashes (“-”) – Not valid in GraphQL
|
||||
|
||||
### Observation
|
||||
|
||||
In the legacy frontend, some enum values contain dashes, for example:
|
||||
|
||||
- CUSTOMER-SERVICE
|
||||
- CROSS-TRAINED
|
||||
- PART-TIME
|
||||
|
||||
But in GraphQL enums only allow letters, numbers, and underscores.
|
||||
The backend had to define them as:
|
||||
|
||||
- CUSTOMER_SERVICE
|
||||
- CROSS_TRAINED
|
||||
- PART_TIME
|
||||
|
||||
### Problem
|
||||
|
||||
When the frontend sends "CUSTOMER-SERVICE" or "CROSS-TRAINED":
|
||||
|
||||
- The backend expects CUSTOMER_SERVICE or CROSS_TRAINED.
|
||||
- There is no match between the frontend value and the DataConnect enum.
|
||||
|
||||
### Impact
|
||||
|
||||
- Enum filters return nothing.
|
||||
- Mutations fail when trying to save invalid enum values.
|
||||
- Compatibility between the Base44 model and the DataConnect schema breaks.
|
||||
|
||||
### Recommendation
|
||||
|
||||
- Standardize all enums to UPPERCASE SNAKE_CASE (e.g., CUSTOMER_SERVICE).
|
||||
- Never use dashes “-” in enum values.
|
||||
|
||||
### Suggestion for Base44 AI
|
||||
|
||||
- Update models so enum values are always generated as
|
||||
UPPERCASE_WITH_UNDERSCORE (e.g., CUSTOMER_SERVICE), without dashes.
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ Field names – Front in snake_case vs DataConnect in camelCase
|
||||
|
||||
### Observation
|
||||
|
||||
The original Base44 frontend uses snake_case field names, for example:
|
||||
|
||||
- contact_number
|
||||
- vendor_id
|
||||
- background_check_status
|
||||
- hub_location
|
||||
|
||||
In DataConnect the schema is camelCase, and although you can map to the actual PostgreSQL column using @col, the GraphQL type remains camelCase, for example:
|
||||
|
||||
- contactNumber (mapped to "contact_number" in Postgres)
|
||||
- vendorId (mapped to "vendor_id")
|
||||
- backgroundCheckStatus (mapped to "background_check_status")
|
||||
- hubLocation (mapped to "hub_location")
|
||||
|
||||
Meaning:
|
||||
|
||||
- In the database (PostgreSQL) names remain snake_case.
|
||||
- In DataConnect and the SDK they are exposed as camelCase.
|
||||
|
||||
### Problem
|
||||
|
||||
The frontend still expects/reads fields like contact_number, but the SDK returns contactNumber.
|
||||
A similar issue happens when the frontend sends payloads in snake_case:
|
||||
|
||||
- The GraphQL schema does not recognize contact_number.
|
||||
- It only accepts contactNumber.
|
||||
|
||||
### Impact
|
||||
|
||||
- UI fails to show data because it reads keys that don’t exist (snake_case).
|
||||
- Mutations fail or ignore fields due to mismatched names.
|
||||
- Filters with snake_case are invalid in GraphQL.
|
||||
|
||||
### Recommendation
|
||||
|
||||
- Agree that **all communication with DataConnect (frontend + SDK) uses camelCase**.
|
||||
- Keep snake_case only at PostgreSQL level using @col, for example:
|
||||
|
||||
employeeName: String @col(name: "employee_name")
|
||||
|
||||
Thus:
|
||||
|
||||
- Frontend / SDK / GraphQL → camelCase (employeeName)
|
||||
- PostgreSQL → snake_case (employee_name)
|
||||
|
||||
### Suggestion for Base44 AI
|
||||
|
||||
- Adjust generated frontend code so it uses camelCase when consuming the new backend.
|
||||
- If Supabase or another backend is still used, document all mappings clearly.
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ Fields used by the frontend but not listed in API Spec v3
|
||||
|
||||
### Observation
|
||||
|
||||
During integration we found that Base44 frontend uses fields not defined in the official document:
|
||||
|
||||
Reference file:
|
||||
docs/03-backend-api-specification-v3.md
|
||||
|
||||
Examples in the Staff entity:
|
||||
|
||||
The frontend sends and displays fields like:
|
||||
|
||||
- notes
|
||||
- rate
|
||||
|
||||
But these fields were not defined in the original v3 specification for Staff.
|
||||
|
||||
### Problem
|
||||
|
||||
- The frontend assumes these fields exist because the old database had them.
|
||||
- The DataConnect schema does not include them.
|
||||
- Sending these values in mutations causes validation errors.
|
||||
|
||||
### Impact
|
||||
|
||||
- Inconsistency between what the UI shows/edits and what is actually persisted.
|
||||
- Risk of losing data the user believes is being saved.
|
||||
- Hard to maintain a 1:1 mapping between the previous Base44 model and the new backend.
|
||||
|
||||
### Recommendation
|
||||
|
||||
- Validate which fields should truly exist for each entity (e.g., Staff).
|
||||
- Align these three items:
|
||||
1. API Spec v3
|
||||
2. DataConnect Schema
|
||||
3. Base44 Frontend
|
||||
|
||||
- If a field is no longer needed, remove it from the frontend.
|
||||
- If important, add it formally to the API Spec and to the DataConnect schema.
|
||||
|
||||
---
|
||||
|
||||
## 5️⃣ DataConnect vs Front – Observed behavior
|
||||
|
||||
1. DataConnect:
|
||||
- Always exposes fields in camelCase.
|
||||
- Enforces enum restrictions exactly as defined (UPPERCASE, no dashes).
|
||||
- Allows mapping to Postgres column names using @col, but GraphQL names remain camelCase.
|
||||
|
||||
2. Base44 Frontend:
|
||||
- Uses snake_case in many areas.
|
||||
- Uses enums in mixed formats (uppercase, camelCase, with dashes).
|
||||
- Contains extra fields not included in API Spec v3.
|
||||
|
||||
---
|
||||
|
||||
## 6️⃣ Suggested fixes (personal criteria)
|
||||
|
||||
1. Enums
|
||||
- Standardize to UPPERCASE_SNAKE_CASE for all enum values.
|
||||
- Apply a normalization layer in the frontend to convert any format into the official one before hitting the backend.
|
||||
|
||||
2. Field names
|
||||
- Migrate the frontend to camelCase for any interaction with DataConnect.
|
||||
- Keep snake_case only at the database layer using @col.
|
||||
|
||||
3. Extra fields
|
||||
- Review all fields the frontend sends and compare with API Spec v3.
|
||||
- Remove or add fields depending on what becomes the “source of truth” (Spec v3).
|
||||
|
||||
4. Documentation
|
||||
- Keep this file updated as the Base44 → DataConnect migration reference.
|
||||
- Add valid payload examples for each entity (Staff, Vendor, Invoice, etc.).
|
||||
|
||||
---
|
||||
|
||||
## 7️⃣ Summary
|
||||
|
||||
- Always generate:
|
||||
- Enums: UPPERCASE_SNAKE_CASE (e.g., FULL_TIME, CUSTOMER_SERVICE).
|
||||
- Fields: camelCase (e.g., contactNumber, hubLocation, backgroundCheckStatus).
|
||||
|
||||
- Avoid:
|
||||
- Dashes “-” in enum values.
|
||||
- Spaces in enum values.
|
||||
|
||||
---
|
||||
|
||||
This document captures the current findings and serves as a guide to fully align the Base44 frontend with the backend based on Firebase Data Connect + PostgreSQL.
|
||||
@@ -22,7 +22,7 @@ const authModule = {
|
||||
// (because your Krow user metadata is stored in the "users" table)
|
||||
let krowUser = null;
|
||||
try {
|
||||
const response = await dcSdk.getUser(dataConnect, { id: fbUser.uid });
|
||||
const response = await dcSdk.getUserById(dataConnect, { id: fbUser.uid });
|
||||
krowUser = response.data?.user || null;
|
||||
} catch (err) {
|
||||
console.warn("Krow user not found in DataConnect, returning Firebase-only info.");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { base44 } from "@/api/base44Client";
|
||||
import { krowSDK } from "@/api/krowSDK";
|
||||
import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createPageUrl } from "@/utils";
|
||||
@@ -21,17 +21,17 @@ export default function CreateEvent() {
|
||||
|
||||
const { data: currentUser } = useQuery({
|
||||
queryKey: ['current-user-create-event'],
|
||||
queryFn: () => base44.auth.me(),
|
||||
queryFn: () => krowSDK.auth.me(),
|
||||
});
|
||||
|
||||
const { data: allEvents = [] } = useQuery({
|
||||
queryKey: ['events-for-conflict-check'],
|
||||
queryFn: () => base44.entities.Event.list(),
|
||||
queryFn: () => krowSDK.entities.Event.list(),
|
||||
initialData: [],
|
||||
});
|
||||
|
||||
const createEventMutation = useMutation({
|
||||
mutationFn: (eventData) => base44.entities.Event.create(eventData),
|
||||
mutationFn: (eventData) => krowSDK.entities.Event.create(eventData),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['events'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['client-events'] });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { base44 } from "@/api/base44Client";
|
||||
import { krowSDK } from "@/api/krowSDK";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { createPageUrl } from "@/utils";
|
||||
@@ -79,7 +79,7 @@ export default function Teams() {
|
||||
|
||||
const { data: user } = useQuery({
|
||||
queryKey: ['current-user-teams'],
|
||||
queryFn: () => base44.auth.me(),
|
||||
queryFn: () => krowSDK.auth.me(),
|
||||
});
|
||||
|
||||
const userRole = user?.user_role || user?.role;
|
||||
@@ -100,7 +100,7 @@ export default function Teams() {
|
||||
*/
|
||||
const { data: userTeam } = useQuery({
|
||||
queryKey: ['user-team', user?.id, userRole],
|
||||
queryFn: async () => {
|
||||
queryFn: async () => {debugger;
|
||||
if (!user?.id) {
|
||||
console.warn("⚠️ No user ID found - cannot fetch team");
|
||||
return null;
|
||||
@@ -108,13 +108,15 @@ export default function Teams() {
|
||||
|
||||
// SECURITY: Fetch ALL teams and filter by owner_id
|
||||
// This ensures only THIS user's team is returned
|
||||
const allTeams = await base44.entities.Team.list('-created_date');
|
||||
|
||||
const result = await krowSDK.entities.Team.list('-created_date');
|
||||
|
||||
const allTeams = result?.data?.teams ?? [];//new, get array from object
|
||||
|
||||
// Find ONLY teams owned by this specific user
|
||||
let team = allTeams.find(t => t.owner_id === user.id);
|
||||
|
||||
debugger;
|
||||
// ISOLATION VERIFICATION
|
||||
if (team && team.owner_id !== user.id) {
|
||||
if (team && team.ownerId !== user.id) {//it had team.owner_id I changed it to team.ownerId
|
||||
console.error("🚨 SECURITY VIOLATION: Team owner mismatch!");
|
||||
return null;
|
||||
}
|
||||
@@ -122,23 +124,29 @@ export default function Teams() {
|
||||
// Auto-create team if doesn't exist (first time user accesses Teams)
|
||||
if (!team && user.id) {
|
||||
console.log(`✅ Creating new isolated team for ${userRole} user: ${user.email}`);
|
||||
const teamName = user.company_name || `${user.full_name}'s Team` || "My Team";
|
||||
|
||||
team = await base44.entities.Team.create({
|
||||
team_name: teamName,
|
||||
owner_id: user.id, // CRITICAL: Links team to THIS user only
|
||||
owner_name: user.full_name || user.email,
|
||||
owner_role: userRole, // Tracks which layer this team belongs to
|
||||
email: user.email,
|
||||
phone: user.phone || "",
|
||||
total_members: 0,
|
||||
active_members: 0,
|
||||
total_hubs: 0,
|
||||
favorite_staff_count: 0,
|
||||
blocked_staff_count: 0,
|
||||
departments: [], // Initialize with an empty array for departments
|
||||
});
|
||||
|
||||
const teamName = user.companyName || `${user.fullName}'s Team` || "My Team";
|
||||
try {
|
||||
team = await krowSDK.entities.Team.create({
|
||||
data: {
|
||||
teamName: teamName,
|
||||
ownerId: user.id, // CRITICAL: Links team to THIS user only
|
||||
ownerName: user.fullName || user.email,
|
||||
ownerRole: userRole, // Tracks which layer this team belongs to
|
||||
//email: user.email,
|
||||
//phone: user.phone || "",
|
||||
//totalMembers: 0,
|
||||
//active_members: 0,
|
||||
//total_hubs: 0,
|
||||
favoriteStaff: 0,//favoriteStaff_count: 0,
|
||||
blockedStaff: 0,//blockedStaff_count: 0,
|
||||
//departments: [], // Initialize with an empty array for departments
|
||||
}
|
||||
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('🔥 Error in user-team queryFn:', err);
|
||||
throw err; // deja que React Query lo maneje como error
|
||||
}
|
||||
console.log(`✅ Team created successfully for ${userRole}: ${team.id}`);
|
||||
}
|
||||
|
||||
@@ -177,7 +185,7 @@ export default function Teams() {
|
||||
}
|
||||
|
||||
// Fetch all members and filter by team_id
|
||||
const allMembers = await base44.entities.TeamMember.list('-created_date');
|
||||
const allMembers = await krowSDK.entities.TeamMember.list('-created_date');
|
||||
|
||||
// SECURITY: Only return members that belong to THIS user's team
|
||||
const filteredMembers = allMembers.filter(m => m.team_id === userTeam.id);
|
||||
@@ -202,7 +210,7 @@ export default function Teams() {
|
||||
queryKey: ['team-invites', userTeam?.id],
|
||||
queryFn: async () => {
|
||||
if (!userTeam?.id) return [];
|
||||
const allInvites = await base44.entities.TeamMemberInvite.list('-invited_date');
|
||||
const allInvites = await krowSDK.entities.TeamMemberInvite.list('-invited_date');
|
||||
return allInvites.filter(inv => inv.team_id === userTeam.id && inv.invite_status === 'pending');
|
||||
},
|
||||
enabled: !!userTeam?.id,
|
||||
@@ -211,7 +219,7 @@ export default function Teams() {
|
||||
|
||||
const { data: allStaff = [] } = useQuery({
|
||||
queryKey: ['staff-for-favorites'],
|
||||
queryFn: () => base44.entities.Staff.list(),
|
||||
queryFn: () => krowSDK.entities.Staff.list(),
|
||||
enabled: !!userTeam?.id,
|
||||
initialData: [],
|
||||
});
|
||||
@@ -220,7 +228,7 @@ export default function Teams() {
|
||||
queryKey: ['team-hubs-main', userTeam?.id],
|
||||
queryFn: async () => {
|
||||
if (!userTeam?.id) return [];
|
||||
const allHubs = await base44.entities.TeamHub.list('-created_date');
|
||||
const allHubs = await krowSDK.entities.TeamHub.list('-created_date');
|
||||
return allHubs.filter(h => h.team_id === userTeam.id);
|
||||
},
|
||||
enabled: !!userTeam?.id,
|
||||
@@ -251,7 +259,7 @@ export default function Teams() {
|
||||
const firstHub = teamHubs.length > 0 ? teamHubs[0].hub_name : "";
|
||||
const firstDept = uniqueDepartments.length > 0 ? uniqueDepartments[0] : "Operations";
|
||||
|
||||
const invite = await base44.entities.TeamMemberInvite.create({
|
||||
const invite = await krowSDK.entities.TeamMemberInvite.create({
|
||||
team_id: userTeam.id,
|
||||
team_name: userTeam.team_name || "Team",
|
||||
invite_code: inviteCode,
|
||||
@@ -295,7 +303,7 @@ export default function Teams() {
|
||||
|
||||
if (data.hub && !existingHub) {
|
||||
// Create new hub with department
|
||||
await base44.entities.TeamHub.create({
|
||||
await krowSDK.entities.TeamHub.create({
|
||||
team_id: userTeam.id,
|
||||
hub_name: data.hub,
|
||||
address: "",
|
||||
@@ -309,7 +317,7 @@ export default function Teams() {
|
||||
const departmentExists = hubDepartments.some(d => d.department_name === data.department);
|
||||
|
||||
if (!departmentExists) {
|
||||
await base44.entities.TeamHub.update(existingHub.id, {
|
||||
await krowSDK.entities.TeamHub.update(existingHub.id, {
|
||||
departments: [...hubDepartments, { department_name: data.department, cost_center: "" }]
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ['team-hubs-main', userTeam?.id] });
|
||||
@@ -318,7 +326,7 @@ export default function Teams() {
|
||||
|
||||
const inviteCode = `TEAM-${Math.floor(10000 + Math.random() * 90000)}`;
|
||||
|
||||
const invite = await base44.entities.TeamMemberInvite.create({
|
||||
const invite = await krowSDK.entities.TeamMemberInvite.create({
|
||||
team_id: userTeam.id,
|
||||
team_name: userTeam.team_name || "Team",
|
||||
invite_code: inviteCode,
|
||||
@@ -335,7 +343,7 @@ export default function Teams() {
|
||||
|
||||
const registerUrl = `${window.location.origin}${createPageUrl('Onboarding')}?invite=${inviteCode}`;
|
||||
|
||||
await base44.integrations.Core.SendEmail({
|
||||
await krowSDK.integrations.Core.SendEmail({
|
||||
from_name: userTeam.team_name || "KROW",
|
||||
to: data.email,
|
||||
subject: `🚀 Welcome to KROW! You've been invited to ${data.hub || userTeam.team_name}`,
|
||||
@@ -439,7 +447,7 @@ export default function Teams() {
|
||||
mutationFn: async (invite) => {
|
||||
const registerUrl = `${window.location.origin}${createPageUrl('Onboarding')}?invite=${invite.invite_code}`;
|
||||
|
||||
await base44.integrations.Core.SendEmail({
|
||||
await krowSDK.integrations.Core.SendEmail({
|
||||
from_name: userTeam.team_name || "Team",
|
||||
to: invite.email,
|
||||
subject: `Reminder: You're invited to join ${userTeam.team_name || 'our team'}!`,
|
||||
@@ -501,7 +509,7 @@ export default function Teams() {
|
||||
});
|
||||
|
||||
const updateMemberMutation = useMutation({
|
||||
mutationFn: ({ id, data }) => base44.entities.TeamMember.update(id, data),
|
||||
mutationFn: ({ id, data }) => krowSDK.entities.TeamMember.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
|
||||
setShowEditMemberDialog(false);
|
||||
@@ -514,7 +522,7 @@ export default function Teams() {
|
||||
});
|
||||
|
||||
const deactivateMemberMutation = useMutation({
|
||||
mutationFn: ({ id }) => base44.entities.TeamMember.update(id, { is_active: false }),
|
||||
mutationFn: ({ id }) => krowSDK.entities.TeamMember.update(id, { is_active: false }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
|
||||
toast({
|
||||
@@ -525,7 +533,7 @@ export default function Teams() {
|
||||
});
|
||||
|
||||
const activateMemberMutation = useMutation({
|
||||
mutationFn: ({ id }) => base44.entities.TeamMember.update(id, { is_active: true }),
|
||||
mutationFn: ({ id }) => krowSDK.entities.TeamMember.update(id, { is_active: true }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
|
||||
toast({
|
||||
@@ -607,7 +615,7 @@ export default function Teams() {
|
||||
}
|
||||
|
||||
// Update the team with new departments list
|
||||
await base44.entities.Team.update(userTeam.id, {
|
||||
await krowSDK.entities.Team.update(userTeam.id, {
|
||||
departments: updatedDepartments
|
||||
});
|
||||
|
||||
@@ -638,7 +646,7 @@ export default function Teams() {
|
||||
const currentDepartments = userTeam.departments || [];
|
||||
const updatedDepartments = currentDepartments.filter(dept => dept !== deptToDelete);
|
||||
|
||||
await base44.entities.Team.update(userTeam.id, {
|
||||
await krowSDK.entities.Team.update(userTeam.id, {
|
||||
departments: updatedDepartments
|
||||
});
|
||||
|
||||
@@ -658,7 +666,7 @@ export default function Teams() {
|
||||
};
|
||||
|
||||
const updateTeamMutation = useMutation({
|
||||
mutationFn: ({ id, data }) => base44.entities.Team.update(id, data),
|
||||
mutationFn: ({ id, data }) => krowSDK.entities.Team.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['user-team', user?.id, userRole] });
|
||||
toast({
|
||||
@@ -761,7 +769,7 @@ export default function Teams() {
|
||||
}, [isGoogleMapsLoaded, showAddHubDialog]);
|
||||
|
||||
const createHubMutation = useMutation({
|
||||
mutationFn: (hubData) => base44.entities.TeamHub.create({
|
||||
mutationFn: (hubData) => krowSDK.entities.TeamHub.create({
|
||||
...hubData,
|
||||
team_id: userTeam.id,
|
||||
is_active: true
|
||||
@@ -2370,14 +2378,14 @@ export default function Teams() {
|
||||
size="lg"
|
||||
onClick={async () => {
|
||||
const updatedDepartments = [...(selectedHubForDept.departments || []), newHubDepartment];
|
||||
await base44.entities.TeamHub.update(selectedHubForDept.id, {
|
||||
await krowSDK.entities.TeamHub.update(selectedHubForDept.id, {
|
||||
departments: updatedDepartments
|
||||
});
|
||||
|
||||
// Also add department to team's global department list
|
||||
const teamDepartments = userTeam?.departments || [];
|
||||
if (!teamDepartments.includes(newHubDepartment.department_name)) {
|
||||
await base44.entities.Team.update(userTeam.id, {
|
||||
await krowSDK.entities.Team.update(userTeam.id, {
|
||||
departments: [...teamDepartments, newHubDepartment.department_name]
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ['user-team', user?.id, userRole] });
|
||||
|
||||
Reference in New Issue
Block a user