Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { EnvironmentConfig } from '~/config'
import { UserSkill, xhrGetAsync } from '~/libs/core'

export type CompletedProfile = {
countryCode?: string
countryName?: string
city?: string
firstName?: string
handle: string
lastName?: string
photoURL?: string
skillCount?: number
userId?: number | string
}

export type CompletedProfilesResponse = {
data: CompletedProfile[]
page: number
perPage: number
total: number
totalPages: number
}

export const DEFAULT_PAGE_SIZE = 50

function normalizeToList(raw: any): any[] {
if (Array.isArray(raw)) {
return raw
}

if (Array.isArray(raw?.data)) {
return raw.data
}

if (Array.isArray(raw?.result?.content)) {
return raw.result.content
}

if (Array.isArray(raw?.result)) {
return raw.result
}

return []
}

function normalizeCompletedProfilesResponse(
raw: any,
Copy link

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider using a more specific type than any for the raw parameter to improve type safety and maintainability.

fallbackPage: number,
fallbackPerPage: number,
): CompletedProfilesResponse {
if (raw && Array.isArray(raw.data)) {
const total: number = Number(raw.total ?? raw.data.length)
const perPage: number = Number(raw.perPage ?? fallbackPerPage)
const page: number = Number(raw.page ?? fallbackPage)
const safePerPage = Number.isFinite(perPage) ? Math.max(perPage, 1) : fallbackPerPage
const safeTotal = Number.isFinite(total) ? Math.max(total, 0) : raw.data.length

return {
data: raw.data,
page: Number.isFinite(page) ? Math.max(page, 1) : fallbackPage,
perPage: safePerPage,
total: safeTotal,
totalPages: Number.isFinite(raw.totalPages)
? Math.max(Number(raw.totalPages), 1)
: Math.max(Math.ceil(safeTotal / safePerPage), 1),
}
}

const rows = normalizeToList(raw)
const total = Number(raw?.total ?? rows.length)
const safeTotal = Number.isFinite(total) ? Math.max(total, 0) : rows.length

return {
data: rows,
page: fallbackPage,
perPage: fallbackPerPage,
total: safeTotal,
totalPages: Math.max(Math.ceil(safeTotal / fallbackPerPage), 1),
}
}

export async function fetchCompletedProfiles(
countryCode: string | undefined,
page: number,
perPage: number,
): Promise<CompletedProfilesResponse> {
const queryParams = new URLSearchParams({
page: String(page),
perPage: String(perPage),
})

if (countryCode) {
queryParams.set('countryCode', countryCode)
}

const response = await xhrGetAsync<any>(
Copy link

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider adding error handling for the xhrGetAsync call to handle potential network or API errors gracefully.

`${EnvironmentConfig.REPORTS_API}/topcoder/completed-profiles?${queryParams.toString()}`,
)

return normalizeCompletedProfilesResponse(response, page, perPage)
}

export async function fetchMemberSkillsData(userId: string | number | undefined): Promise<UserSkill[]> {
if (!userId) {
Copy link

Choose a reason for hiding this comment

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

[💡 correctness]
The check for !userId could be more explicit by using userId == null to handle both null and undefined cases.

return []
}

const baseUrl = `${EnvironmentConfig.API.V5}/standardized-skills`
const url = `${baseUrl}/user-skills/${userId}?disablePagination=true`

try {
return await xhrGetAsync<UserSkill[]>(url)
} catch {
// If skills API fails, return empty array to not block the page
return []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
table {
width: 100%;
border-collapse: collapse;
min-width: 420px;
min-width: 1120px;
Copy link

Choose a reason for hiding this comment

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

[⚠️ design]
Increasing the min-width of the table from 420px to 1120px could affect the layout on smaller screens. Ensure that this change has been tested across different screen sizes to maintain responsiveness.

}

th,
Expand All @@ -106,9 +106,66 @@

td {
color: $black-100;
vertical-align: middle;
}

tr:last-child td {
border-bottom: 0;
}
}

.memberCell {
display: flex;
align-items: center;
gap: $sp-2;
}

.avatar {
width: 28px;
height: 28px;
border-radius: 50%;
object-fit: cover;
border: 1px solid $black-20;
}

.paginationRow {
display: flex;
align-items: center;
justify-content: space-between;
gap: $sp-3;

@include ltemd {
flex-direction: column;
align-items: flex-start;
}
}

.paginationInfo {
color: $black-60;
font-size: 14px;
line-height: 20px;
}

.paginationButtons {
display: flex;
align-items: center;
gap: $sp-2;
}

.skillsList {
display: flex;
flex-wrap: wrap;
gap: $sp-2;
}

.skillTag {
display: inline-block;
background: $black-5;
border: 1px solid $black-20;
border-radius: $sp-1;
padding: $sp-1 $sp-2;
font-size: 12px;
line-height: 16px;
color: $black-80;
white-space: nowrap;
}
Loading
Loading