feat: add pagination support for project lists in dialogs

Add server-side pagination to EntityGrid component for projects, enabling
infinite scrolling to load all available projects instead of stopping after
the initial batch.

Changes:
- EntityGrid: Add loadMoreCallback prop to trigger server-side loading when
  scroll reaches end of loaded projects
- OnboardMeetingSetupView: Update loadProjects() to support pagination with
  beforeId parameter and add handleLoadMoreProjects() callback
- MeetingProjectDialog: Accept and pass through loadMoreCallback to EntityGrid
- GiftedDialog: Add pagination support to loadProjects() and
  handleLoadMoreProjects() callback
- EntitySelectionStep: Accept and pass through loadMoreCallback prop to
  EntityGrid when showing projects

This ensures users can access all projects in MeetingProjectDialog and
GiftedDialog by automatically loading more as they scroll, matching the
behavior already present in DiscoverView.

All project uses of EntityGrid now use pagination by default.
This commit is contained in:
Jose Olarte III
2025-11-12 17:10:03 +08:00
parent bf7ee630d0
commit 6bf4055c2f
5 changed files with 165 additions and 12 deletions

View File

@@ -274,6 +274,7 @@
:all-my-dids="allMyDids"
:all-contacts="allContacts"
:notify="$notify"
:load-more-callback="handleLoadMoreProjects"
@assign="handleProjectLinkAssigned"
/>
@@ -785,40 +786,80 @@ export default class OnboardMeetingView extends Vue {
/**
* Load projects from the API
* @param beforeId - Optional rowId for pagination (loads projects before this ID)
*/
async loadProjects() {
async loadProjects(beforeId?: string) {
try {
const headers = await getHeaders(this.activeDid);
const url = `${this.apiServer}/api/v2/report/plans`;
let url = `${this.apiServer}/api/v2/report/plans`;
if (beforeId) {
url += `?beforeId=${encodeURIComponent(beforeId)}`;
}
const resp = await this.axios.get(url, { headers });
if (resp.status === 200 && resp.data.data) {
this.allProjects = resp.data.data.map(
const newProjects = resp.data.data.map(
(plan: {
name: string;
description: string;
image?: string;
handleId: string;
issuerDid: string;
rowId?: string;
}) => ({
name: plan.name,
description: plan.description,
image: plan.image,
handleId: plan.handleId,
issuerDid: plan.issuerDid,
rowId: plan.rowId,
}),
);
if (beforeId) {
// Pagination: append new projects
this.allProjects.push(...newProjects);
} else {
// Initial load: replace array
this.allProjects = newProjects;
}
}
} catch (error) {
this.$logAndConsole(
"Error loading projects: " + errorStringForLog(error),
true,
);
// Don't show error to user - just leave projects empty
this.allProjects = [];
// Don't show error to user - just leave projects empty (or keep existing if pagination)
if (!beforeId) {
this.allProjects = [];
}
}
}
/**
* Handle loading more projects when EntityGrid reaches the end
* Called by MeetingProjectDialog via loadMoreCallback
* @param entities - Current array of projects
*/
async handleLoadMoreProjects(
entities: Array<{
handleId: string;
rowId?: string;
}>,
): Promise<void> {
if (entities.length === 0) {
return;
}
const lastProject = entities[entities.length - 1];
if (!lastProject.rowId) {
// No rowId means we can't paginate - likely end of data
return;
}
await this.loadProjects(lastProject.rowId);
}
/**
* Computed property for selected project
* Derives the project from projectLink by finding it in allProjects