Skip to content

Commit 03b795a

Browse files
authored
Merge pull request #1514 from topcoder-platform/PM-4198_customer-portal-completed-profiles-report-updates
PM-4198 add pagination & member details to custmer portal results
2 parents e0bfe3f + 6b85742 commit 03b795a

File tree

3 files changed

+371
-96
lines changed

3 files changed

+371
-96
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { EnvironmentConfig } from '~/config'
2+
import { UserSkill, xhrGetAsync } from '~/libs/core'
3+
4+
export type CompletedProfile = {
5+
countryCode?: string
6+
countryName?: string
7+
city?: string
8+
firstName?: string
9+
handle: string
10+
lastName?: string
11+
photoURL?: string
12+
skillCount?: number
13+
userId?: number | string
14+
}
15+
16+
export type CompletedProfilesResponse = {
17+
data: CompletedProfile[]
18+
page: number
19+
perPage: number
20+
total: number
21+
totalPages: number
22+
}
23+
24+
export const DEFAULT_PAGE_SIZE = 50
25+
26+
function normalizeToList(raw: any): any[] {
27+
if (Array.isArray(raw)) {
28+
return raw
29+
}
30+
31+
if (Array.isArray(raw?.data)) {
32+
return raw.data
33+
}
34+
35+
if (Array.isArray(raw?.result?.content)) {
36+
return raw.result.content
37+
}
38+
39+
if (Array.isArray(raw?.result)) {
40+
return raw.result
41+
}
42+
43+
return []
44+
}
45+
46+
function normalizeCompletedProfilesResponse(
47+
raw: any,
48+
fallbackPage: number,
49+
fallbackPerPage: number,
50+
): CompletedProfilesResponse {
51+
if (raw && Array.isArray(raw.data)) {
52+
const total: number = Number(raw.total ?? raw.data.length)
53+
const perPage: number = Number(raw.perPage ?? fallbackPerPage)
54+
const page: number = Number(raw.page ?? fallbackPage)
55+
const safePerPage = Number.isFinite(perPage) ? Math.max(perPage, 1) : fallbackPerPage
56+
const safeTotal = Number.isFinite(total) ? Math.max(total, 0) : raw.data.length
57+
58+
return {
59+
data: raw.data,
60+
page: Number.isFinite(page) ? Math.max(page, 1) : fallbackPage,
61+
perPage: safePerPage,
62+
total: safeTotal,
63+
totalPages: Number.isFinite(raw.totalPages)
64+
? Math.max(Number(raw.totalPages), 1)
65+
: Math.max(Math.ceil(safeTotal / safePerPage), 1),
66+
}
67+
}
68+
69+
const rows = normalizeToList(raw)
70+
const total = Number(raw?.total ?? rows.length)
71+
const safeTotal = Number.isFinite(total) ? Math.max(total, 0) : rows.length
72+
73+
return {
74+
data: rows,
75+
page: fallbackPage,
76+
perPage: fallbackPerPage,
77+
total: safeTotal,
78+
totalPages: Math.max(Math.ceil(safeTotal / fallbackPerPage), 1),
79+
}
80+
}
81+
82+
export async function fetchCompletedProfiles(
83+
countryCode: string | undefined,
84+
page: number,
85+
perPage: number,
86+
): Promise<CompletedProfilesResponse> {
87+
const queryParams = new URLSearchParams({
88+
page: String(page),
89+
perPage: String(perPage),
90+
})
91+
92+
if (countryCode) {
93+
queryParams.set('countryCode', countryCode)
94+
}
95+
96+
const response = await xhrGetAsync<any>(
97+
`${EnvironmentConfig.REPORTS_API}/topcoder/completed-profiles?${queryParams.toString()}`,
98+
)
99+
100+
return normalizeCompletedProfilesResponse(response, page, perPage)
101+
}
102+
103+
export async function fetchMemberSkillsData(userId: string | number | undefined): Promise<UserSkill[]> {
104+
if (!userId) {
105+
return []
106+
}
107+
108+
const baseUrl = `${EnvironmentConfig.API.V5}/standardized-skills`
109+
const url = `${baseUrl}/user-skills/${userId}?disablePagination=true`
110+
111+
try {
112+
return await xhrGetAsync<UserSkill[]>(url)
113+
} catch {
114+
// If skills API fails, return empty array to not block the page
115+
return []
116+
}
117+
}

src/apps/customer-portal/src/pages/profile-completion/ProfileCompletionPage/ProfileCompletionPage.module.scss

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
table {
8787
width: 100%;
8888
border-collapse: collapse;
89-
min-width: 420px;
89+
min-width: 1120px;
9090
}
9191

9292
th,
@@ -106,9 +106,66 @@
106106

107107
td {
108108
color: $black-100;
109+
vertical-align: middle;
109110
}
110111

111112
tr:last-child td {
112113
border-bottom: 0;
113114
}
114115
}
116+
117+
.memberCell {
118+
display: flex;
119+
align-items: center;
120+
gap: $sp-2;
121+
}
122+
123+
.avatar {
124+
width: 28px;
125+
height: 28px;
126+
border-radius: 50%;
127+
object-fit: cover;
128+
border: 1px solid $black-20;
129+
}
130+
131+
.paginationRow {
132+
display: flex;
133+
align-items: center;
134+
justify-content: space-between;
135+
gap: $sp-3;
136+
137+
@include ltemd {
138+
flex-direction: column;
139+
align-items: flex-start;
140+
}
141+
}
142+
143+
.paginationInfo {
144+
color: $black-60;
145+
font-size: 14px;
146+
line-height: 20px;
147+
}
148+
149+
.paginationButtons {
150+
display: flex;
151+
align-items: center;
152+
gap: $sp-2;
153+
}
154+
155+
.skillsList {
156+
display: flex;
157+
flex-wrap: wrap;
158+
gap: $sp-2;
159+
}
160+
161+
.skillTag {
162+
display: inline-block;
163+
background: $black-5;
164+
border: 1px solid $black-20;
165+
border-radius: $sp-1;
166+
padding: $sp-1 $sp-2;
167+
font-size: 12px;
168+
line-height: 16px;
169+
color: $black-80;
170+
white-space: nowrap;
171+
}

0 commit comments

Comments
 (0)