Skip to content

Commit df21189

Browse files
authored
feat: simplify member api [CM-762] (#3564)
1 parent 4b0a05d commit df21189

6 files changed

Lines changed: 228 additions & 705 deletions

File tree

backend/src/services/member/memberOrganizationsService.ts

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import SequelizeRepository from '@/database/repositories/sequelizeRepository'
2121

2222
import { IServiceOptions } from '../IServiceOptions'
2323

24-
type IOrganizationSummary = Pick<IOrganization, 'id' | 'displayName' | 'logo'>
24+
type IOrganizationSummary = Pick<IOrganization, 'id' | 'displayName' | 'logo' | 'createdAt'>
2525

2626
export default class MemberOrganizationsService extends LoggerBase {
2727
options: IServiceOptions
@@ -64,7 +64,12 @@ export default class MemberOrganizationsService extends LoggerBase {
6464
in: orgIds,
6565
},
6666
},
67-
fields: [OrganizationField.ID, OrganizationField.DISPLAY_NAME, OrganizationField.LOGO],
67+
fields: [
68+
OrganizationField.ID,
69+
OrganizationField.DISPLAY_NAME,
70+
OrganizationField.LOGO,
71+
OrganizationField.CREATED_AT,
72+
],
6873
})
6974
}
7075

@@ -84,15 +89,64 @@ export default class MemberOrganizationsService extends LoggerBase {
8489
{},
8590
)
8691

87-
// Format the results
88-
return memberOrganizations.map((mo) => ({
89-
...(orgByid[mo.organizationId] || {}),
90-
id: mo.organizationId,
91-
memberOrganizations: {
92-
...mo,
93-
affiliationOverride: affiliationOverrides.find((ao) => ao.memberOrganizationId === mo.id),
94-
},
95-
}))
92+
// Format the results and order by dateStart and dateEnd
93+
const allOrganizations = memberOrganizations
94+
.filter((mo) => orgByid[mo.organizationId]) // Only include non-deleted organizations
95+
.map((mo) => ({
96+
...(orgByid[mo.organizationId] || {}),
97+
id: mo.organizationId,
98+
memberOrganizations: {
99+
...mo,
100+
affiliationOverride: affiliationOverrides.find((ao) => ao.memberOrganizationId === mo.id),
101+
},
102+
}))
103+
.sort((a, b) => {
104+
if (!a || !b) {
105+
return 0
106+
}
107+
108+
// Sort by dateStart (newest first), then by dateEnd (active first - null dateEnd comes first)
109+
const aDateStart = a.memberOrganizations.dateStart
110+
? new Date(a.memberOrganizations.dateStart).getTime()
111+
: 0
112+
const bDateStart = b.memberOrganizations.dateStart
113+
? new Date(b.memberOrganizations.dateStart).getTime()
114+
: 0
115+
116+
if (aDateStart !== bDateStart) {
117+
return bDateStart - aDateStart // Newest dateStart first
118+
}
119+
120+
// If dateStart is the same, prioritize active memberships (null dateEnd)
121+
const aDateEnd = a.memberOrganizations.dateEnd
122+
const bDateEnd = b.memberOrganizations.dateEnd
123+
124+
if (!aDateEnd && bDateEnd) return -1 // a is active, b is not
125+
if (aDateEnd && !bDateEnd) return 1 // b is active, a is not
126+
127+
// Both have null dateEnd and dateStart - sort by createdAt, then alphabetically
128+
if (!aDateEnd && !bDateEnd && aDateStart === 0 && bDateStart === 0) {
129+
// First try to sort by createdAt
130+
const aCreatedAt = a.createdAt ? new Date(a.createdAt).getTime() : 0
131+
const bCreatedAt = b.createdAt ? new Date(b.createdAt).getTime() : 0
132+
133+
if (aCreatedAt !== bCreatedAt) {
134+
return bCreatedAt - aCreatedAt // Newest createdAt first
135+
}
136+
137+
// If createdAt is also the same, sort alphabetically by displayName
138+
const aName = (a.displayName || '').toLowerCase()
139+
const bName = (b.displayName || '').toLowerCase()
140+
return aName.localeCompare(bName)
141+
}
142+
143+
if (!aDateEnd && !bDateEnd) return 0 // both are active with same dateStart
144+
145+
// Both have dateEnd, sort by dateEnd (newest first)
146+
return new Date(bDateEnd).getTime() - new Date(aDateEnd).getTime()
147+
})
148+
149+
return allOrganizations
96150
}
97151

98152
// Member organization creation

frontend/src/modules/contributor/helpers/contributor.helpers.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { MemberIdentity } from '@/modules/member/types/Member';
2-
import memberOrder from '@/shared/modules/identities/config/identitiesOrder/member';
3-
import { Contributor } from '@/modules/contributor/types/Contributor';
41
import { lfIdentities } from '@/config/identities';
2+
import { Contributor } from '@/modules/contributor/types/Contributor';
3+
import { MemberIdentity } from '@/modules/member/types/Member';
54
import { dateHelper } from '@/shared/date-helper/date-helper';
5+
import memberOrder from '@/shared/modules/identities/config/identitiesOrder/member';
66

77
const useContributorHelpers = () => {
88
const avatar = (contributor: Contributor) => contributor.attributes?.avatarUrl?.default;
@@ -66,15 +66,7 @@ const useContributorHelpers = () => {
6666
}));
6767
};
6868

69-
const activeOrganization = (contributor: Contributor) => {
70-
const { organizations } = contributor;
71-
72-
return organizations.find((org) => org.memberOrganizations.affiliationOverride?.isPrimaryWorkExperience
73-
&& !!org.memberOrganizations.dateStart
74-
&& !org.memberOrganizations.dateEnd)
75-
|| organizations.find((org) => !!org.memberOrganizations.dateStart && !org.memberOrganizations.dateEnd)
76-
|| organizations.find((org) => !org.memberOrganizations.dateStart && !org.memberOrganizations.dateEnd) || null;
77-
};
69+
const activeOrganization = (contributor: Contributor) => contributor.organizations;
7870

7971
return {
8072
avatar,

0 commit comments

Comments
 (0)