Skip to content

[PT2025BMHW-119][SuperAdminUI,SharedUI] feat: Implement Global Users Management Page#147

Merged
breftejk merged 11 commits intodevelopfrom
PT2025BMHW-119
Feb 5, 2026
Merged

[PT2025BMHW-119][SuperAdminUI,SharedUI] feat: Implement Global Users Management Page#147
breftejk merged 11 commits intodevelopfrom
PT2025BMHW-119

Conversation

@babesrap
Copy link
Collaborator

@babesrap babesrap commented Feb 1, 2026

 - Create new UsersPage in SuperAdmin application
 - Implement UsersTable component with server-side sorting and pagination
 - Implement UsersFilters component for searching by name/email and filtering by status
 - Integrate existing useUsers hook from shared package for data fetching
 - Fix duplicated query definitions by removing redundant queries.ts file
 - Add action placeholders for User Details, Deactivate, Activate, and Reset Password
 - Ensure responsive design and consistent UI using shared components

cos tam cos tam

Implements edit mode for the multi-step tenant form.

- Reuses CreateTenantDialog for editing existing tenants
- Pre-populates form with existing tenant data
- Adds visual indicators for modified fields (orange dot)
- Implements concurrent edit detection and warning system
- Handles immutable fields (domain) in edit mode
- Adds support for 'create' and 'edit' modes in TenantFormDialog

Jira: PT2025BMHW-112
* [PT2025BMHW-113][SharedUI,SuperAdminUI] feat: Implement Delete Tenant Confirmation & Refactor Tenants Page

     - Create DeleteTenantDialog component with premium UI
     - Add security check requiring tenant name confirmation
     - Display impact warnings (Active Users count)
     - Show irreversible action alert
     - Refactor TenantsPage:
       - Extract TenantsTable component
       - Extract TenantsFilters component
       - Simplify main page logic
…n Assignment & Management

* [PT2025BMHW-118][SharedUI,SuperAdminUI,Backend] feat: Implement Tenant Admin Assignment & Management

     - Backend: Add GetUsers endpoint to UsersController for user search
     - SharedUI: Add useUsers hook and tenant admin assignment mutations
     - SuperAdminUI: Implement AssignAdminModal with user search
     - SuperAdminUI: Implement EditTenantModal for tenant details updates
     - SuperAdminUI: Add functionality to unassign tenant admins
     - SuperAdminUI: Integrate new modals into TenantDetailPage
…ment Page

* [PT2025BMHW-119][SuperAdminUI,SharedUI] feat: Implement Global Users Management Page

     - Create new UsersPage in SuperAdmin
     - Implement UsersTable with sorting and pagination
     - Implement UsersFilters for search and status filtering
     - Integrate existing useUsers hook from shared package
     - Remove duplicate queries.ts file in shared/features/users
@breftejk breftejk enabled auto-merge (squash) February 5, 2026 21:34
@breftejk breftejk requested a review from Copilot February 5, 2026 21:36
@breftejk
Copy link
Owner

breftejk commented Feb 5, 2026

@copilot fix conflicts with develop

Copy link
Contributor

Copilot AI commented Feb 5, 2026

@breftejk I've opened a new pull request, #149, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a global users management page for the SuperAdmin application and refactors the existing tenants management components for better maintainability. The implementation adds server-side pagination, filtering, and sorting capabilities to the users list, along with placeholder action handlers for user management operations.

Changes:

  • Added new Users management page with table, filters, and pagination in SuperAdmin UI
  • Added backend API endpoint for fetching paginated user lists
  • Refactored Tenants components by extracting TenantsTable, TenantsFilters, and dialog components
  • Added new modals for tenant management (Edit, Delete, Assign Admin)
  • Updated Vite configurations with package alias resolution
  • Added mutation hooks for assigning/unassigning tenant admins

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
Infrastructure/NGOPlatform.SuperAdmin/NGOPlatform.SuperAdmin.Api/Controllers/UsersController.cs Added GET endpoint for paginated users list using CQRS pattern
Infrastructure/NGOPlatform.AppHost/appsettings.Development.json Changed mobile platform setting from "ios" to "no-mobile"
Frontend/packages/shared/src/lib/mocks/mock-users-large.ts Added empty mock users file (has encoding issues)
Frontend/packages/shared/src/lib/mocks/mock-tenants-large.ts Added mock data for 800 tenants for testing
Frontend/packages/shared/src/features/tenant-admins/mutations/index.ts Added useAssignTenantAdmin and useUnassignTenantAdmin hooks with query invalidation
Frontend/apps/tenantadmin/vite.config.ts Added package alias resolution and formatting improvements
Frontend/apps/superadmin/vite.config.ts Added package alias resolution and formatting improvements
Frontend/apps/superadmin/src/components/users/UsersTable.tsx New component for displaying paginated users table with sorting
Frontend/apps/superadmin/src/components/users/UsersPage.tsx New main users management page with filters and pagination
Frontend/apps/superadmin/src/components/users/UsersFilters.tsx New component for user search and status filtering
Frontend/apps/superadmin/src/components/tenants/TenantsTable.tsx Extracted table component from TenantsPage for reusability
Frontend/apps/superadmin/src/components/tenants/TenantsPage.tsx Refactored to use extracted components, reduced from 510 to 248 lines
Frontend/apps/superadmin/src/components/tenants/TenantsFilters.tsx Extracted filters component for tenant search and status
Frontend/apps/superadmin/src/components/tenants/TenantFormDialog.tsx Enhanced with edit mode, dirty field tracking, and concurrent edit detection
Frontend/apps/superadmin/src/components/tenants/TenantDetailPage.tsx Added edit modal and admin assignment/removal functionality
Frontend/apps/superadmin/src/components/tenants/EditTenantModal.tsx New modal for editing tenant details
Frontend/apps/superadmin/src/components/tenants/DeleteTenantDialog.tsx New confirmation dialog for tenant deletion with safeguards
Frontend/apps/superadmin/src/components/tenants/AssignAdminModal.tsx New modal for assigning existing users as tenant admins
Comments suppressed due to low confidence (3)

Frontend/apps/superadmin/src/components/tenants/TenantFormDialog.tsx:58

  • The TypeScript ignore comment on line 57 suggests there's a type mismatch with the useTenant hook. Instead of suppressing the type error, the issue should be fixed. Either the useTenant hook should be updated to support the optional parameters being passed, or this code should be refactored to match the expected signature.
    Frontend/apps/superadmin/src/components/tenants/TenantFormDialog.tsx:196
  • Concurrency check implementation issue: The concurrent edit detection compares updatedAt timestamps for exact equality, which is fragile. Minor clock skew, serialization differences, or database precision differences could cause false positives. Consider using a version number/ETag approach, or allowing a small time tolerance, or implementing optimistic locking with a proper version field in the backend.
    Frontend/apps/superadmin/src/components/tenants/TenantFormDialog.tsx:46
  • Unused variable warning.

Comment on lines 1 to 148
import { features, type User } from '@ngo-platform/shared';
import { useEffect, useState, type FC } from 'react';
import { UsersFilters } from './UsersFilters';
import { UsersTable, type UserSortField } from './UsersTable';

const ITEMS_PER_PAGE = 10;

export const UsersPage: FC = () => {
return (
<div className="p-8">
<div className="mb-6">
<h1 className="text-3xl font-bold text-neutral-900 dark:text-white mb-2">Users</h1>
<p className="text-neutral-600 dark:text-neutral-400">Manage platform users</p>
</div>
<Card>
<CardContent className="p-8 text-center">
<Icon name="users" size={48} className="mx-auto text-neutral-400 mb-4" />
<p className="text-lg text-neutral-600 dark:text-neutral-400">Users management coming soon...</p>
</CardContent>
</Card>
</div>
);
// State
const [searchQuery, setSearchQuery] = useState('');
const [statusFilter, setStatusFilter] = useState<'All' | 'Active' | 'Inactive'>('All');
const [sortField, setSortField] = useState<UserSortField>('createdAt');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
const [currentPage, setCurrentPage] = useState(1);

// Queries
// Convert status filter to boolean or undefined
const isActive = statusFilter === 'All' ? undefined : statusFilter === 'Active';

const { data: usersResponse, isLoading, error, refetch } = features.useUsers({
page: currentPage,
pageSize: ITEMS_PER_PAGE,
search: searchQuery || undefined,
isActive: isActive,
sortBy: sortField,
sortOrder: sortOrder,
});

const users: User[] = usersResponse?.items ?? [];
const totalPages = usersResponse?.totalPages ?? 1;
const totalCount = usersResponse?.totalCount ?? 0;

// Reset to page 1 when filters change
useEffect(() => {
setCurrentPage(1);
}, [searchQuery, statusFilter, sortField, sortOrder]);

// Handlers
const handleSort = (field: UserSortField) => {
if (sortField === field) {
setSortOrder((prev) => (prev === 'asc' ? 'desc' : 'asc'));
} else {
setSortField(field);
setSortOrder('asc');
}
};

const handleView = (user: User) => {
// Navigate to user details or open modal
// For now, simple console log or alert as per plan
console.log('View user', user);
// navigate(`/users/${user.id}`); // If we had a detail page
};

const handleDeactivate = async (user: User) => {
if (confirm(`Are you sure you want to deactivate ${user.fullName}?`)) {
try {
// await deactivateUser.mutateAsync(user.id);
console.log('Deactivating user', user.id);
// refetch();
} catch (e) {
console.error(e);
}
}
};

const handleActivate = async (user: User) => {
if (confirm(`Are you sure you want to activate ${user.fullName}?`)) {
console.log('Activating user', user.id);
// await activateUser.mutateAsync(user.id);
// refetch();
}
};

const handleResetPassword = async (user: User) => {
if (confirm(`Send password reset email to ${user.email}?`)) {
console.log('Resetting password for', user.id);
}
};

const goToPage = (page: number) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
}
};

return (
<div className="p-6 lg:p-8">
{/* Header */}
<div className="mb-6 flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-neutral-900 dark:text-white mb-2">Users</h1>
<p className="text-neutral-600 dark:text-neutral-400">Manage all users across the platform</p>
</div>
</div>

{/* Filters */}
<UsersFilters
searchQuery={searchQuery}
onSearchChange={setSearchQuery}
statusFilter={statusFilter}
onStatusChange={setStatusFilter}
onClearAll={() => {
setSearchQuery('');
setStatusFilter('All');
}}
/>

{/* Table */}
<UsersTable
users={users}
isLoading={isLoading}
error={error instanceof Error ? error : null}
totalCount={totalCount}
sortField={sortField}
sortOrder={sortOrder}
onSort={handleSort}
onView={handleView}
onDeactivate={handleDeactivate}
onActivate={handleActivate}
onResetPassword={handleResetPassword}
/>

{/* Pagination */}
{(usersResponse?.totalCount ?? 0) > 0 && (
<div className="mt-4 flex items-center justify-center gap-2">
<button
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
className="px-3 py-1 rounded border border-neutral-300 dark:border-neutral-600 disabled:opacity-50 hover:bg-neutral-50 dark:hover:bg-neutral-800"
>
Previous
</button>
<span className="text-sm text-neutral-600 dark:text-neutral-400">
Page {currentPage} of {totalPages}
</span>
<button
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
className="px-3 py-1 rounded border border-neutral-300 dark:border-neutral-600 disabled:opacity-50 hover:bg-neutral-50 dark:hover:bg-neutral-800"
>
Next
</button>
</div>
)}
</div>
);
};
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new users management page. The PR adds UsersPage, UsersTable, and UsersFilters components but doesn't include any corresponding test files. Based on the repository's testing conventions (xUnit for backend, Jest for frontend), tests should be added for these new components, especially for the filtering, sorting, and pagination logic.

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +77
const handleView = (user: User) => {
// Navigate to user details or open modal
// For now, simple console log or alert as per plan
console.log('View user', user);
// navigate(`/users/${user.id}`); // If we had a detail page
};

const handleDeactivate = async (user: User) => {
if (confirm(`Are you sure you want to deactivate ${user.fullName}?`)) {
try {
// await deactivateUser.mutateAsync(user.id);
console.log('Deactivating user', user.id);
// refetch();
} catch (e) {
console.error(e);
}
}
};

const handleActivate = async (user: User) => {
if (confirm(`Are you sure you want to activate ${user.fullName}?`)) {
console.log('Activating user', user.id);
// await activateUser.mutateAsync(user.id);
// refetch();
}
};

const handleResetPassword = async (user: User) => {
if (confirm(`Send password reset email to ${user.email}?`)) {
console.log('Resetting password for', user.id);
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder action handlers: The handlers for view, deactivate, activate, and reset password are all placeholders that only log to console. While the PR description mentions "action placeholders", these should either be implemented or clearly marked as TODO with tracking tickets, rather than having silent console.log statements that won't be visible to users.

Suggested change
const handleView = (user: User) => {
// Navigate to user details or open modal
// For now, simple console log or alert as per plan
console.log('View user', user);
// navigate(`/users/${user.id}`); // If we had a detail page
};
const handleDeactivate = async (user: User) => {
if (confirm(`Are you sure you want to deactivate ${user.fullName}?`)) {
try {
// await deactivateUser.mutateAsync(user.id);
console.log('Deactivating user', user.id);
// refetch();
} catch (e) {
console.error(e);
}
}
};
const handleActivate = async (user: User) => {
if (confirm(`Are you sure you want to activate ${user.fullName}?`)) {
console.log('Activating user', user.id);
// await activateUser.mutateAsync(user.id);
// refetch();
}
};
const handleResetPassword = async (user: User) => {
if (confirm(`Send password reset email to ${user.email}?`)) {
console.log('Resetting password for', user.id);
// TODO: Implement user view navigation (e.g. navigate to user details page).
const handleView = (user: User) => {
// Placeholder implementation: inform user that this action is not yet available.
alert(`Viewing details for "${user.fullName}" is not available yet.`);
// Example future implementation:
// navigate(`/users/${user.id}`);
};
// TODO: Implement user deactivation (e.g. call deactivate user API and refetch list).
const handleDeactivate = async (user: User) => {
if (confirm(`Are you sure you want to deactivate ${user.fullName}?`)) {
// Placeholder implementation: inform user that this action is not yet available.
alert(`Deactivation for "${user.fullName}" is not available yet.`);
}
};
// TODO: Implement user activation (e.g. call activate user API and refetch list).
const handleActivate = async (user: User) => {
if (confirm(`Are you sure you want to activate ${user.fullName}?`)) {
// Placeholder implementation: inform user that this action is not yet available.
alert(`Activation for "${user.fullName}" is not available yet.`);
}
};
// TODO: Implement password reset (e.g. trigger reset email via API).
const handleResetPassword = async (user: User) => {
if (confirm(`Send password reset email to ${user.email}?`)) {
// Placeholder implementation: inform user that this action is not yet available.
alert(`Password reset for "${user.email}" is not available yet.`);

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +103
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-300 transition-colors user-select-none"
// onClick={() => onSort('isActive')} // Hook might not support sort by status yet, but UI can show it
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Status column header has sorting UI hints (cursor-pointer, hover states) but the onClick handler is commented out. This creates a confusing user experience where the column appears sortable but doesn't respond to clicks. Either implement the sorting functionality or remove the sorting UI affordances from this column.

Suggested change
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-300 transition-colors user-select-none"
// onClick={() => onSort('isActive')} // Hook might not support sort by status yet, but UI can show it
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider"
// onClick={() => onSort('isActive')} // Hook might not support sort by status yet

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +130
<div className="w-10 h-10 bg-secondary-100 dark:bg-secondary-900/30 text-secondary-600 dark:text-secondary-400 rounded-full flex items-center justify-center font-bold text-sm flex-shrink-0 border border-secondary-200 dark:border-secondary-800">
{user.firstName?.charAt(0)}{user.lastName?.charAt(0)}
</div>
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference issue: The code uses user.firstName?.charAt(0) and user.lastName?.charAt(0) to create initials, but the backend UserListItemDto defines FirstName and LastName as non-nullable strings (with default value string.Empty). If either field is empty, charAt(0) will return an empty string, resulting in no initials being displayed. Consider adding a fallback, such as using the first character of email or a default icon.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +122
<thead className="bg-neutral-50 dark:bg-neutral-800 border-b border-neutral-200 dark:border-neutral-700">
<tr>
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-300 transition-colors user-select-none"
onClick={() => onSort('firstName')} // Simplification: sorting by name usually goes by first name or generic "name"
>
<div className="flex items-center gap-1 group">
User
<span className="opacity-0 group-hover:opacity-100 transition-opacity">
{getSortIcon('firstName')}
</span>
</div>
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider">
Role
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider">
Tenant
</th>
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-300 transition-colors user-select-none"
// onClick={() => onSort('isActive')} // Hook might not support sort by status yet, but UI can show it
>
Status
</th>
<th
className="px-6 py-3 text-left text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-300 transition-colors user-select-none"
onClick={() => onSort('createdAt')}
>
<div className="flex items-center gap-1 group">
Created
<span className="opacity-0 group-hover:opacity-100 transition-opacity">
{getSortIcon('createdAt')}
</span>
</div>
</th>
<th className="px-6 py-3 text-right text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility issue: The sortable table headers lack proper ARIA attributes. Sortable columns should include aria-sort="ascending|descending|none" to indicate the current sort state to screen reader users. Additionally, the column headers should have role="columnheader" and the clickable area should include aria-label describing the sorting action.

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +144
{/* Pagination */}
{(usersResponse?.totalCount ?? 0) > 0 && (
<div className="mt-4 flex items-center justify-center gap-2">
<button
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
className="px-3 py-1 rounded border border-neutral-300 dark:border-neutral-600 disabled:opacity-50 hover:bg-neutral-50 dark:hover:bg-neutral-800"
>
Previous
</button>
<span className="text-sm text-neutral-600 dark:text-neutral-400">
Page {currentPage} of {totalPages}
</span>
<button
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
className="px-3 py-1 rounded border border-neutral-300 dark:border-neutral-600 disabled:opacity-50 hover:bg-neutral-50 dark:hover:bg-neutral-800"
>
Next
</button>
</div>
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility issue: The pagination buttons lack proper ARIA labels. Buttons with only "Previous" and "Next" text should include aria-label attributes to provide context about what is being paginated (e.g., "Previous page of users", "Next page of users") for screen reader users.

Copilot uses AI. Check for mistakes.
Comment on lines 171 to 183
<Button variant="ghost" size="sm" onClick={() => onView(user)} title="View Details">
<Icon name="eye" size={16} />
</Button>
<Button variant="ghost" size="sm" onClick={() => onResetPassword(user)} title="Reset Password">
<Icon name="key" size={16} />
</Button>
{user.isActive ? (
<Button variant="ghost" size="sm" className="text-error-600 hover:text-error-700 hover:bg-error-50 dark:hover:bg-error-900/20" onClick={() => onDeactivate(user)} title="Deactivate User">
<Icon name="userX" size={16} />
</Button>
) : (
<Button variant="ghost" size="sm" className="text-success-600 hover:text-success-700 hover:bg-success-50 dark:hover:bg-success-900/20" onClick={() => onActivate(user)} title="Activate User">
<Icon name="checkCircle" size={16} />
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility issue: Action buttons only show icons without visible text labels. While they have title attributes for tooltips, screen reader users may not benefit from this. Consider adding visually-hidden text labels or using aria-label attributes to describe each action (e.g., aria-label="View user details for {user.fullName}").

Suggested change
<Button variant="ghost" size="sm" onClick={() => onView(user)} title="View Details">
<Icon name="eye" size={16} />
</Button>
<Button variant="ghost" size="sm" onClick={() => onResetPassword(user)} title="Reset Password">
<Icon name="key" size={16} />
</Button>
{user.isActive ? (
<Button variant="ghost" size="sm" className="text-error-600 hover:text-error-700 hover:bg-error-50 dark:hover:bg-error-900/20" onClick={() => onDeactivate(user)} title="Deactivate User">
<Icon name="userX" size={16} />
</Button>
) : (
<Button variant="ghost" size="sm" className="text-success-600 hover:text-success-700 hover:bg-success-50 dark:hover:bg-success-900/20" onClick={() => onActivate(user)} title="Activate User">
<Icon name="checkCircle" size={16} />
<Button
variant="ghost"
size="sm"
onClick={() => onView(user)}
title="View Details"
aria-label="View details"
>
<Icon name="eye" size={16} aria-hidden="true" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => onResetPassword(user)}
title="Reset Password"
aria-label="Reset password"
>
<Icon name="key" size={16} aria-hidden="true" />
</Button>
{user.isActive ? (
<Button
variant="ghost"
size="sm"
className="text-error-600 hover:text-error-700 hover:bg-error-50 dark:hover:bg-error-900/20"
onClick={() => onDeactivate(user)}
title="Deactivate User"
aria-label="Deactivate user"
>
<Icon name="userX" size={16} aria-hidden="true" />
</Button>
) : (
<Button
variant="ghost"
size="sm"
className="text-success-600 hover:text-success-700 hover:bg-success-50 dark:hover:bg-success-900/20"
onClick={() => onActivate(user)}
title="Activate User"
aria-label="Activate user"
>
<Icon name="checkCircle" size={16} aria-hidden="true" />

Copilot uses AI. Check for mistakes.
"DefaultConnection": "Server=tcp:ngo-platform.database.windows.net,1433;Initial Catalog=ngo-platform-dev;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=\"Active Directory Default\";"
},
"ASPIRE_MOBILE_PLATFORM": "ios",
"ASPIRE_MOBILE_PLATFORM": "no-mobile",
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The configuration change from "ios" to "no-mobile" appears intentional for development purposes, but this should be documented in the commit message or PR description why this change was made. If this is just a personal development preference, it should not be committed to the repository as it affects all developers.

Suggested change
"ASPIRE_MOBILE_PLATFORM": "no-mobile",
"ASPIRE_MOBILE_PLATFORM": "ios",

Copilot uses AI. Check for mistakes.
Comment on lines 22 to 29
resolve: {
alias: {
"@ngo-platform/shared": path.resolve(
__dirname,
"../../packages/shared/src/index.ts",
),
},
},
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vite.config.ts files are adding a resolve alias for "@ngo-platform/shared" which might conflict with the workspace's native package resolution. Since this is a Yarn workspace monorepo, the package should be resolvable without this alias. This manual alias could cause issues where the IDE and build tools have different resolution paths. Verify if this alias is actually necessary or if it can be removed.

Suggested change
resolve: {
alias: {
"@ngo-platform/shared": path.resolve(
__dirname,
"../../packages/shared/src/index.ts",
),
},
},

Copilot uses AI. Check for mistakes.
// Convert status filter to boolean or undefined
const isActive = statusFilter === 'All' ? undefined : statusFilter === 'Active';

const { data: usersResponse, isLoading, error, refetch } = features.useUsers({
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable refetch.

Suggested change
const { data: usersResponse, isLoading, error, refetch } = features.useUsers({
const { data: usersResponse, isLoading, error } = features.useUsers({

Copilot uses AI. Check for mistakes.
@breftejk
Copy link
Owner

breftejk commented Feb 5, 2026

@copilot fix conflicts with develop

Copy link
Contributor

Copilot AI commented Feb 5, 2026

@breftejk I've opened a new pull request, #156, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 3 commits February 5, 2026 21:56
…develop and resolve conflicts

Merge conflicts resolved:
- Accepted tenant sorting implementation from develop (backend + frontend)
- Removed vite.config.ts alias (not needed with Yarn workspaces)
- Reverted ASPIRE_MOBILE_PLATFORM to 'ios' (default)
- Kept our Users Management implementation (UsersPage, UsersController)
- Kept our refactored Tenants components (TenantFormDialog, TenantsFilters, etc.)
- Kept our tenant admin assignment features (AssignAdminModal, UnassignModal)
- Accepted DashboardPage tenant count feature from develop
- Kept mobile HTTP support in config for SSL certificate issues
Co-authored-by: Nikutsuki <70451760+Nikutsuki@users.noreply.github.com>
[PT2025BMHW-119][SuperAdminUI,SharedUI,Backend,Infrastructure] Merge develop and resolve conflicts
@breftejk breftejk merged commit 47b1f90 into develop Feb 5, 2026
4 checks passed
@breftejk breftejk deleted the PT2025BMHW-119 branch February 5, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants