Improve the frontend and fix TODOs
This commit is contained in:
@@ -4,8 +4,7 @@ import { Users, Plus, Search, Shield, Trash2, Crown, UserCheck } from 'lucide-re
|
||||
import { Button, StatusCard, getStatusColor, StatsGrid, SearchAndFilter, type FilterConfig } from '../../../../components/ui';
|
||||
import AddTeamMemberModal from '../../../../components/domain/team/AddTeamMemberModal';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
import { useTeamMembers, useAddTeamMember, useRemoveTeamMember, useUpdateMemberRole, useTenantAccess } from '../../../../api/hooks/tenant';
|
||||
import { useAllUsers } from '../../../../api/hooks/user';
|
||||
import { useTeamMembers, useAddTeamMember, useAddTeamMemberWithUserCreation, useRemoveTeamMember, useUpdateMemberRole, useTenantAccess } from '../../../../api/hooks/tenant';
|
||||
import { useAuthUser } from '../../../../stores/auth.store';
|
||||
import { useCurrentTenant, useCurrentTenantAccess } from '../../../../stores/tenant.store';
|
||||
import { useToast } from '../../../../hooks/ui/useToast';
|
||||
@@ -26,15 +25,12 @@ const TeamPage: React.FC = () => {
|
||||
currentUser?.id || '',
|
||||
{ enabled: !!tenantId && !!currentUser?.id && !currentTenantAccess }
|
||||
);
|
||||
|
||||
|
||||
const { data: teamMembers = [], isLoading } = useTeamMembers(tenantId, false, { enabled: !!tenantId }); // Show all members including inactive
|
||||
const { data: allUsers = [], error: allUsersError, isLoading: allUsersLoading } = useAllUsers({
|
||||
retry: false, // Don't retry on permission errors
|
||||
staleTime: 0 // Always fresh check for permissions
|
||||
});
|
||||
|
||||
|
||||
// Mutations
|
||||
const addMemberMutation = useAddTeamMember();
|
||||
const addMemberWithUserMutation = useAddTeamMemberWithUserCreation();
|
||||
const removeMemberMutation = useRemoveTeamMember();
|
||||
const updateRoleMutation = useUpdateMemberRole();
|
||||
|
||||
@@ -46,37 +42,35 @@ const TeamPage: React.FC = () => {
|
||||
|
||||
|
||||
// Enhanced team members that includes owner information
|
||||
// Note: Backend now enriches members with user info, so we just need to ensure owner is present
|
||||
const enhancedTeamMembers = useMemo(() => {
|
||||
const members = [...teamMembers];
|
||||
|
||||
// If tenant owner is not in the members list, add them
|
||||
|
||||
// If tenant owner is not in the members list, add them as a placeholder
|
||||
if (currentTenant?.owner_id) {
|
||||
const ownerInMembers = members.find(m => m.user_id === currentTenant.owner_id);
|
||||
if (!ownerInMembers) {
|
||||
// Find owner user data
|
||||
const ownerUser = allUsers.find(u => u.id === currentTenant.owner_id);
|
||||
if (ownerUser) {
|
||||
// Add owner as a member
|
||||
members.push({
|
||||
id: `owner-${currentTenant.owner_id}`,
|
||||
tenant_id: tenantId,
|
||||
user_id: currentTenant.owner_id,
|
||||
role: TENANT_ROLES.OWNER,
|
||||
is_active: true,
|
||||
joined_at: currentTenant.created_at,
|
||||
user_email: ownerUser.email,
|
||||
user_full_name: ownerUser.full_name,
|
||||
user: ownerUser, // Add full user object for compatibility
|
||||
} as any);
|
||||
}
|
||||
// Add owner as a member with basic info
|
||||
// Note: The backend should ideally include the owner in the members list
|
||||
members.push({
|
||||
id: `owner-${currentTenant.owner_id}`,
|
||||
tenant_id: tenantId,
|
||||
user_id: currentTenant.owner_id,
|
||||
role: TENANT_ROLES.OWNER,
|
||||
is_active: true,
|
||||
joined_at: currentTenant.created_at,
|
||||
user_email: null, // Backend will enrich this
|
||||
user_full_name: null, // Backend will enrich this
|
||||
user: null,
|
||||
} as any);
|
||||
} else if (ownerInMembers.role !== TENANT_ROLES.OWNER) {
|
||||
// Update existing member to owner role
|
||||
ownerInMembers.role = TENANT_ROLES.OWNER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return members;
|
||||
}, [teamMembers, currentTenant, allUsers, tenantId]);
|
||||
}, [teamMembers, currentTenant, tenantId]);
|
||||
|
||||
const roles = [
|
||||
{ value: 'all', label: 'Todos los Roles', count: enhancedTeamMembers.length },
|
||||
@@ -160,36 +154,54 @@ const TeamPage: React.FC = () => {
|
||||
const getMemberActions = (member: any) => {
|
||||
const actions = [];
|
||||
|
||||
// Role change actions (only for non-owners and if user can manage team)
|
||||
// Primary action - View details (always available)
|
||||
// This will be implemented in the future to show detailed member info modal
|
||||
// For now, we can comment it out as there's no modal yet
|
||||
// actions.push({
|
||||
// label: 'Ver Detalles',
|
||||
// icon: Eye,
|
||||
// priority: 'primary' as const,
|
||||
// onClick: () => {
|
||||
// // TODO: Implement member details modal
|
||||
// console.log('View member details:', member.user_id);
|
||||
// },
|
||||
// });
|
||||
|
||||
// Contextual role change actions (only for non-owners and if user can manage team)
|
||||
if (canManageTeam && member.role !== TENANT_ROLES.OWNER) {
|
||||
if (member.role !== TENANT_ROLES.ADMIN) {
|
||||
// Promote/demote to most logical next role
|
||||
if (member.role === TENANT_ROLES.VIEWER) {
|
||||
// Viewer -> Member (promote)
|
||||
actions.push({
|
||||
label: 'Hacer Admin',
|
||||
icon: Shield,
|
||||
onClick: () => handleUpdateRole(member.user_id, TENANT_ROLES.ADMIN),
|
||||
priority: 'secondary' as const,
|
||||
});
|
||||
}
|
||||
|
||||
if (member.role !== TENANT_ROLES.MEMBER) {
|
||||
actions.push({
|
||||
label: 'Hacer Miembro',
|
||||
icon: Users,
|
||||
label: 'Promover a Miembro',
|
||||
icon: UserCheck,
|
||||
onClick: () => handleUpdateRole(member.user_id, TENANT_ROLES.MEMBER),
|
||||
priority: 'secondary' as const,
|
||||
});
|
||||
}
|
||||
|
||||
if (member.role !== TENANT_ROLES.VIEWER) {
|
||||
actions.push({
|
||||
label: 'Hacer Observador',
|
||||
onClick: () => handleUpdateRole(member.user_id, TENANT_ROLES.VIEWER),
|
||||
priority: 'tertiary' as const,
|
||||
});
|
||||
} else if (member.role === TENANT_ROLES.MEMBER) {
|
||||
// Member -> Admin (promote) or Member -> Viewer (demote)
|
||||
if (isOwner) {
|
||||
actions.push({
|
||||
label: 'Promover a Admin',
|
||||
icon: Shield,
|
||||
onClick: () => handleUpdateRole(member.user_id, TENANT_ROLES.ADMIN),
|
||||
priority: 'secondary' as const,
|
||||
});
|
||||
}
|
||||
} else if (member.role === TENANT_ROLES.ADMIN) {
|
||||
// Admin -> Member (demote) - only owner can do this
|
||||
if (isOwner) {
|
||||
actions.push({
|
||||
label: 'Cambiar a Miembro',
|
||||
icon: Users,
|
||||
onClick: () => handleUpdateRole(member.user_id, TENANT_ROLES.MEMBER),
|
||||
priority: 'secondary' as const,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove member action (only for owners)
|
||||
// Remove member action (only for owners and non-owner members)
|
||||
if (isOwner && member.role !== TENANT_ROLES.OWNER) {
|
||||
actions.push({
|
||||
label: 'Remover',
|
||||
@@ -199,7 +211,7 @@ const TeamPage: React.FC = () => {
|
||||
handleRemoveMember(member.user_id);
|
||||
}
|
||||
},
|
||||
priority: 'tertiary' as const,
|
||||
priority: 'secondary' as const,
|
||||
destructive: true,
|
||||
});
|
||||
}
|
||||
@@ -216,11 +228,6 @@ const TeamPage: React.FC = () => {
|
||||
return matchesRole && matchesSearch;
|
||||
});
|
||||
|
||||
// Available users for adding (exclude current members)
|
||||
const availableUsers = allUsers.filter(u =>
|
||||
!enhancedTeamMembers.some(m => m.user_id === u.id)
|
||||
);
|
||||
|
||||
// Force reload tenant access if missing
|
||||
React.useEffect(() => {
|
||||
if (currentTenant?.id && !currentTenantAccess) {
|
||||
@@ -241,10 +248,6 @@ const TeamPage: React.FC = () => {
|
||||
directTenantAccess,
|
||||
effectiveTenantAccess,
|
||||
tenantAccess: effectiveTenantAccess?.role,
|
||||
allUsers: allUsers.length,
|
||||
allUsersError,
|
||||
allUsersLoading,
|
||||
availableUsers: availableUsers.length,
|
||||
enhancedTeamMembers: enhancedTeamMembers.length
|
||||
});
|
||||
|
||||
@@ -458,13 +461,31 @@ const TeamPage: React.FC = () => {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
await addMemberMutation.mutateAsync({
|
||||
tenantId,
|
||||
userId: userData.userId,
|
||||
role: userData.role,
|
||||
});
|
||||
// Use appropriate mutation based on whether we're creating a user
|
||||
if (userData.createUser) {
|
||||
await addMemberWithUserMutation.mutateAsync({
|
||||
tenantId,
|
||||
memberData: {
|
||||
create_user: true,
|
||||
email: userData.email!,
|
||||
full_name: userData.fullName!,
|
||||
password: userData.password!,
|
||||
phone: userData.phone,
|
||||
role: userData.role,
|
||||
language: 'es',
|
||||
timezone: 'Europe/Madrid'
|
||||
}
|
||||
});
|
||||
addToast('Usuario creado y agregado exitosamente', { type: 'success' });
|
||||
} else {
|
||||
await addMemberMutation.mutateAsync({
|
||||
tenantId,
|
||||
userId: userData.userId!,
|
||||
role: userData.role,
|
||||
});
|
||||
addToast('Miembro agregado exitosamente', { type: 'success' });
|
||||
}
|
||||
|
||||
addToast('Miembro agregado exitosamente', { type: 'success' });
|
||||
setShowAddForm(false);
|
||||
setSelectedUserToAdd('');
|
||||
setSelectedRoleToAdd(TENANT_ROLES.MEMBER);
|
||||
@@ -473,11 +494,14 @@ const TeamPage: React.FC = () => {
|
||||
// Limit error already toasted above
|
||||
throw error;
|
||||
}
|
||||
addToast('Error al agregar miembro', { type: 'error' });
|
||||
addToast(
|
||||
userData.createUser ? 'Error al crear usuario' : 'Error al agregar miembro',
|
||||
{ type: 'error' }
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}}
|
||||
availableUsers={availableUsers}
|
||||
availableUsers={[]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user