Skip to content

Commit b939978

Browse files
committed
Fix export for group contributor over 500 users
1 parent 9090950 commit b939978

File tree

2 files changed

+109
-46
lines changed
  • community-dashboard/app

2 files changed

+109
-46
lines changed

community-dashboard/app/components/ItemSelectInput/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
146146
const variables = useMemo(() => ({
147147
search: debouncedSearchText,
148148
offset: 0,
149-
limit: 5,
149+
limit: LIMIT,
150150
}), [debouncedSearchText]);
151151

152152
const {

community-dashboard/app/views/UserGroupDashboard/index.tsx

Lines changed: 108 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback } from 'react';
1+
import React, { useCallback, useMemo, useState } from 'react';
22
import { gql, useQuery, useLazyQuery } from '@apollo/client';
33
import { encodeDate } from '@togglecorp/fujs';
44
import { useParams } from 'react-router-dom';
@@ -20,11 +20,15 @@ import {
2020
UserGroupStatsQueryVariables,
2121
FilteredUserGroupStatsQuery,
2222
FilteredUserGroupStatsQueryVariables,
23+
UserMembershipsExportQuery,
24+
UserMembershipsExportQueryVariables,
2325
} from '#generated/types';
2426
import { defaultPagePerItemOptions } from '#utils/common';
2527

2628
import styles from './styles.css';
2729

30+
const EXPORT_LIMIT = 500;
31+
2832
const USER_GROUP_STATS = gql`
2933
query UserGroupStats($pk: ID!, $limit: Int!, $offset: Int!) {
3034
userGroup(pk: $pk) {
@@ -100,6 +104,30 @@ const FILTERED_USER_GROUP_STATS = gql`
100104
}
101105
`;
102106

107+
const USER_MEMBERSHIPS_EXPORT = gql`
108+
query UserMembershipsExport(
109+
$pk: ID!,
110+
$limit: Int!,
111+
$offset: Int!,
112+
) {
113+
userGroup(pk: $pk) {
114+
userMemberships(pagination: { limit: $limit, offset: $offset }) {
115+
count
116+
limit
117+
offset
118+
items {
119+
userId
120+
username
121+
isActive
122+
totalMappingProjects
123+
totalSwipeTime
124+
totalSwipes
125+
}
126+
}
127+
}
128+
}
129+
`;
130+
103131
type UserGroupMember = NonNullable<NonNullable<NonNullable<UserGroupStatsQuery['userGroup']>['userMemberships']>['items']>[number];
104132

105133
function memberKeySelector(member: UserGroupMember) {
@@ -120,10 +148,15 @@ interface Props {
120148
className?: string;
121149
}
122150

151+
type UserMembershipType = NonNullable<NonNullable<UserMembershipsExportQuery['userGroup']>['userMemberships']>['items'];
152+
123153
function UserGroupDashboard(props: Props) {
124154
const { className } = props;
125155

126156
const { userGroupId } = useParams<{ userGroupId: string | undefined }>();
157+
const [userMembershipsData, setUserMembershipsData] = useState<UserMembershipType>([]);
158+
const [exportPending, setExportPending] = useState<boolean>(false);
159+
127160
const [
128161
dateRange,
129162
setDateRange,
@@ -146,6 +179,7 @@ function UserGroupDashboard(props: Props) {
146179

147180
const [activePage, setActivePage] = React.useState(1);
148181
const [pagePerItem, setPagePerItem] = React.useState(10);
182+
const [offset, setOffset] = useState<number>(EXPORT_LIMIT);
149183

150184
const {
151185
data: userGroupStats,
@@ -162,49 +196,78 @@ function UserGroupDashboard(props: Props) {
162196
},
163197
);
164198

165-
const [
166-
getUserGroupStatsDownload,
167-
{
168-
loading: userGroupStatsDownloadLoading,
169-
},
170-
] = useLazyQuery<UserGroupStatsQuery, UserGroupStatsQueryVariables>(
171-
USER_GROUP_STATS,
172-
{
173-
variables: userGroupId ? {
199+
const userGroupExportVariable = useMemo(
200+
(): UserMembershipsExportQueryVariables | undefined => (
201+
userGroupId ? {
174202
pk: userGroupId,
175-
limit: 500, // NOTE this is a temporary fix we need to do recursive fetch later
203+
limit: EXPORT_LIMIT,
176204
offset: 0,
177-
} : undefined,
178-
onCompleted: (data) => {
179-
const userGroupData = [
180-
['User', 'Total swipes', 'Project contributed', 'Time spent(mins)'],
181-
...(data.userGroup.userMemberships.items.map((user) => (
182-
[
183-
user.username,
184-
user.totalSwipes,
185-
user.totalMappingProjects,
186-
user.totalSwipeTime,
187-
]
188-
)) ?? [])];
189-
let csvContent = '';
190-
userGroupData.forEach((row) => {
191-
csvContent += `${row.join(',')} \n`;
192-
});
193-
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8,' });
194-
const objUrl = URL.createObjectURL(blob);
195-
const link = document.createElement('a');
196-
link.href = objUrl;
197-
link.download = `${userGroupStats?.userGroup?.name ?? 'users'}.csv`;
198-
document.body.appendChild(link);
199-
link.dispatchEvent(
200-
new MouseEvent('click', {
201-
bubbles: true,
202-
cancelable: true,
203-
view: window,
204-
}),
205-
);
206-
document.body.removeChild(link);
207-
window.URL.revokeObjectURL(objUrl);
205+
} : undefined
206+
), [userGroupId],
207+
);
208+
209+
const [
210+
exportUserMembership,
211+
] = useLazyQuery<UserMembershipsExportQuery, UserGroupStatsQueryVariables>(
212+
USER_MEMBERSHIPS_EXPORT,
213+
{
214+
variables: userGroupExportVariable,
215+
onCompleted: (response) => {
216+
const result = response?.userGroup?.userMemberships;
217+
const userMembershipsCount = response?.userGroup?.userMemberships?.count ?? 0;
218+
219+
setUserMembershipsData((prevValue) => [...prevValue, ...result?.items ?? []]);
220+
setOffset((prevValue) => prevValue + EXPORT_LIMIT);
221+
222+
if (userMembershipsData?.length < userMembershipsCount) {
223+
setExportPending(true);
224+
exportUserMembership({
225+
variables: userGroupId ? ({
226+
pk: userGroupId,
227+
limit: EXPORT_LIMIT,
228+
offset,
229+
}) : undefined,
230+
});
231+
}
232+
233+
if (userMembershipsData?.length === userMembershipsCount) {
234+
const userGroupData = [
235+
['User', 'Total swipes', 'Project contributed', 'Time spent(mins)'],
236+
...(userMembershipsData?.map((user) => (
237+
[
238+
user.username,
239+
user.totalSwipes,
240+
user.totalMappingProjects,
241+
user.totalSwipeTime,
242+
]
243+
)) ?? []),
244+
];
245+
let csvContent = '';
246+
userGroupData.forEach((row) => {
247+
csvContent += `${row.join(',')} \n`;
248+
});
249+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8,' });
250+
const objUrl = URL.createObjectURL(blob);
251+
const link = document.createElement('a');
252+
link.href = objUrl;
253+
link.download = `${userGroupStats?.userGroup?.name ?? 'users'}.csv`;
254+
document.body.appendChild(link);
255+
link.dispatchEvent(
256+
new MouseEvent('click', {
257+
bubbles: true,
258+
cancelable: true,
259+
view: window,
260+
}),
261+
);
262+
document.body.removeChild(link);
263+
window.URL.revokeObjectURL(objUrl);
264+
setExportPending(false);
265+
}
266+
},
267+
onError: (err) => {
268+
// NOTE: we don't show any alert on failure and success for now
269+
// eslint-disable-next-line no-console
270+
console.log('some error ocoured', err);
208271
},
209272
},
210273
);
@@ -278,11 +341,11 @@ function UserGroupDashboard(props: Props) {
278341
Group Members
279342
</Heading>
280343
<Button
281-
disabled={userGroupStatsDownloadLoading}
282-
onClick={getUserGroupStatsDownload}
344+
disabled={exportPending}
345+
onClick={exportUserMembership}
283346
name={undefined}
284347
>
285-
{ userGroupStatsDownloadLoading ? 'Exporting' : 'Export' }
348+
{ exportPending ? 'Exporting' : 'Export' }
286349
</Button>
287350
</div>
288351
<div className={styles.membersContainer}>

0 commit comments

Comments
 (0)