Skip to content
Open
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
Expand Up @@ -26,7 +26,7 @@ export const aboutApi = directusApi.injectEndpoints({
queryFn: async () => {
try {
const members = await client.request<Member[]>(
readItems('members', { limit: 500 }),
readItems('members_v2', { limit: 500 }),
);

const normalize = (input: unknown) =>
Expand Down
104 changes: 57 additions & 47 deletions frontend-next-migration/src/entities/Member/api/mappers.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { organizeMembers } from './mappers';
import { Member, Team, Department } from '@/entities/Member/model/types/types';
import { Member, Team, Department, MemberRole } from '@/entities/Member/model/types/types';

const mockTeams: Team[] = [
{
id: 1,
name: 'Development',
translations: [
{ id: 101, teams_id: 1, languages_code: 'en-US', team: 'Development' },
{ id: 102, teams_id: 1, languages_code: 'fi-FI', team: 'Ohjelmistokehitys' },
{ id: 101, teams_v2_id: 1, languages_code: 'en-US', name: 'Development' },
{ id: 102, teams_v2_id: 1, languages_code: 'fi-FI', name: 'Ohjelmistokehitys' },
],
members: [],
departments: [],
Expand All @@ -16,8 +16,8 @@ const mockTeams: Team[] = [
id: 2,
name: 'Game Design',
translations: [
{ id: 103, teams_id: 2, languages_code: 'en-US', team: 'Game Design' },
{ id: 104, teams_id: 2, languages_code: 'fi-FI', team: 'Pelisuunnittelu' },
{ id: 103, teams_v2_id: 2, languages_code: 'en-US', name: 'Game Design' },
{ id: 104, teams_v2_id: 2, languages_code: 'fi-FI', name: 'Pelisuunnittelu' },
],
members: [],
departments: [],
Expand All @@ -33,27 +33,32 @@ describe('organizeMembers', () => {
github: 'https://github.com/Jonroi',
linkedin: 'https://www.linkedin.com/in/joni-roine/',
website: 'https://jonroi.netlify.app/',
team: mockTeams[0],
department: {
id: 10,
name: 'Website Developer',
translations: [
{
id: 110,
departments_id: 10,
languages_code: 'en-US',
department: 'Website Developer',
},
{
id: 111,
departments_id: 10,
languages_code: 'fi-FI',
department: 'VerkkosivukehittΓ€jΓ€',
},
],
members: [],
} as Department,
translations: [],
roles: [
{
id: 1,
team: mockTeams[0],
department: {
id: 10,
name: 'Website Developer',
translations: [
{
id: 110,
departments_v2_id: 10,
languages_code: 'en-US',
name: 'Website Developer',
},
{
id: 111,
departments_v2_id: 10,
languages_code: 'fi-FI',
name: 'VerkkosivukehittΓ€jΓ€',
},
],
members: [],
} as Department,
translations: [],
} as MemberRole,
],
},
{
id: 2,
Expand All @@ -62,27 +67,32 @@ describe('organizeMembers', () => {
github: 'https://github.com/AliceSmith',
linkedin: 'https://www.linkedin.com/in/alice-smith/',
website: 'https://alicesmith.com/',
team: mockTeams[1],
department: {
id: 20,
name: 'Game Developer',
translations: [
{
id: 120,
departments_id: 20,
languages_code: 'en-US',
department: 'Game Developer',
},
{
id: 121,
departments_id: 20,
languages_code: 'fi-FI',
department: 'PelikehittΓ€jΓ€',
},
],
members: [],
} as Department,
translations: [],
roles: [
{
id: 2,
team: mockTeams[1],
department: {
id: 20,
name: 'Game Developer',
translations: [
{
id: 120,
departments_v2_id: 20,
languages_code: 'en-US',
name: 'Game Developer',
},
{
id: 121,
departments_v2_id: 20,
languages_code: 'fi-FI',
name: 'PelikehittΓ€jΓ€',
},
],
members: [],
} as Department,
translations: [],
} as MemberRole,
],
},
];

Expand Down
167 changes: 129 additions & 38 deletions frontend-next-migration/src/entities/Member/api/mappers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { faGithub, faLinkedin, faInstagram, faFacebook } from '@fortawesome/free-brands-svg-icons';
import { faGlobe, faEnvelope } from '@fortawesome/free-solid-svg-icons';
import { Member, Team } from '@/entities/Member/model/types/types';
import { Member, Team, MemberRole, Department } from '@/entities/Member/model/types/types';
import { getDepartmentTranslation, getTeamTranslation, getLanguageCode } from './translations';

/**
Expand Down Expand Up @@ -81,11 +81,103 @@ const fiDepartmentOrder = [
*/

/**
* Organizes members into teams and departments based on their properties,
* Creates or retrieves a team from the teams map.
*/
const getOrCreateTeam = (
teamsMap: Map<number, Team>,
memberTeam: Team,
fullLanguageCode: string,
): Team => {
let team = teamsMap.get(memberTeam.id);
if (!team) {
const teamName = getTeamTranslation(memberTeam.translations || [], fullLanguageCode);
team = {
id: memberTeam.id,
name: teamName || '',
translations: memberTeam.translations || [],
members: [],
departments: [],
};
teamsMap.set(memberTeam.id, team);
}
return team;
};

/**
* Creates or retrieves a department within a team.
*/
const getOrCreateDepartment = (
team: Team,
memberDepartment: Department,
fullLanguageCode: string,
): Department => {
let department = team.departments.find(
(departmentItem) => departmentItem.id === memberDepartment.id,
);
if (!department) {
const departmentName = getDepartmentTranslation(
memberDepartment.translations || [],
fullLanguageCode,
);
department = {
id: memberDepartment.id,
name: departmentName || '',
translations: memberDepartment.translations || [],
members: [],
};
team.departments.push(department);
}
return department;
};

/**
* Adds a member to a team or department if not already present.
*/
const addMemberToTeamOrDepartment = (
member: Member,
team: Team,
department: Department | null,
): void => {
if (department) {
if (!department.members.find((memberItem: Member) => memberItem.id === member.id)) {
department.members.push(member);
}
} else {
if (!team.members.find((memberItem: Member) => memberItem.id === member.id)) {
team.members.push(member);
}
}
};

/**
* Processes a single role and adds the member to the appropriate team/department.
*/
const processRole = (
role: MemberRole,
member: Member,
teamsMap: Map<number, Team>,
fullLanguageCode: string,
): void => {
const memberTeam = role.team;
if (!memberTeam) {
return;
}

const team = getOrCreateTeam(teamsMap, memberTeam, fullLanguageCode);
const memberDepartment = role.department;
const department = memberDepartment
? getOrCreateDepartment(team, memberDepartment, fullLanguageCode)
: null;

addMemberToTeamOrDepartment(member, team, department);
};

/**
* Organizes members into teams and departments based on their roles,
* and sorts both the members alphabetically within their teams and departments,
* as well as the teams based on a predefined order dictated by language.
*
* @param {Member[]} members - An array of member objects, each containing associated team and department data.
* @param {Member[]} members - An array of member objects, each containing roles with team and department data.
* @param {string} lng - The language code used to determine which language to use for translations and sorting.
* @returns {OrganizedData} The organized data containing teams mapped by their IDs.
*/
Expand All @@ -98,40 +190,13 @@ export const organizeMembers = (members: Member[], lng: string) => {
const departmentOrder = lng === 'fi' ? fiDepartmentOrder : enDepartmentOrder;

members.forEach((member: Member) => {
const memberTeam = member.team;
const memberDepartment = member.department;

if (memberTeam) {
let team = teamsMap.get(memberTeam.id);
if (!team) {
const teamName = getTeamTranslation(
memberTeam.translations || [],
fullLanguageCode,
);

team = { ...memberTeam, name: teamName, members: [], departments: [] };
teamsMap.set(memberTeam.id, team);
}

if (memberDepartment) {
let department = team.departments.find(
(departmentItem) => departmentItem.id === memberDepartment.id,
);
if (!department) {
const departmentName = getDepartmentTranslation(
memberDepartment.translations || [],
fullLanguageCode,
);

department = { ...memberDepartment, name: departmentName, members: [] };
team.departments.push(department);
}

department.members.push(member);
} else {
team.members.push(member);
}
if (!member.roles || member.roles.length === 0) {
return;
}

member.roles.forEach((role: MemberRole) => {
processRole(role, member, teamsMap, fullLanguageCode);
});
});
teamsMap.forEach((team) => {
team.members.sort((a, b) => a.name.localeCompare(b.name));
Expand All @@ -155,10 +220,36 @@ export const organizeMembers = (members: Member[], lng: string) => {
department.members.sort((a, b) => a.name.localeCompare(b.name));
});
});
const sortedTeams = Array.from(teamsMap.values()).sort((a, b) => {
// Sort teams according to predefined order
// Teams not in the order array go to the end, sorted by name
// Filter out teams with empty names
const validTeams = Array.from(teamsMap.values()).filter(
(team) => team.name && team.name.trim() !== '',
);

// Sort teams according to predefined order
// Teams not in the order array go to the end, sorted by name
const sortedTeams = validTeams.sort((a, b) => {
const indexA = order.indexOf(a.name);
const indexB = order.indexOf(b.name);
return indexA - indexB;

// Both teams are in the order array - sort by position
if (indexA !== -1 && indexB !== -1) {
return indexA - indexB;
}

// Team A is in order, Team B is not - A comes first
if (indexA !== -1 && indexB === -1) {
return -1;
}

// Team B is in order, Team A is not - B comes first
if (indexA === -1 && indexB !== -1) {
return 1;
}

// Neither team is in order array - sort alphabetically
return a.name.localeCompare(b.name);
});

return { teamsMap: new Map(sortedTeams.map((team) => [team.id, team])) };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const client = createDirectus(directusBaseUrl).with(rest());
* @module memberTeamsApi
*
* @endpoint getMemberTeams
* Endpoint to fetch member teams from the Directus `teams` collection.
* Endpoint to fetch member teams from the Directus `teams_v2` collection.
* Retrieves information about teams, including their translations.
*
* @returns {Record<string, any>[]} Response containing an array of teams.
Expand All @@ -25,7 +25,7 @@ const memberTeamsApi = directusApi.injectEndpoints({
getMemberTeams: builder.query({
queryFn: async (_arg: void) => {
const teams = await client.request(
readItems('teams', {
readItems('teams_v2', {
fields: ['id', 'translations.*'],
deep: { translations: true },
}),
Expand Down
14 changes: 8 additions & 6 deletions frontend-next-migration/src/entities/Member/api/membersApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@ const membersApi = directusApi.injectEndpoints({
queryFn: async (): Promise<{ data: Member[] } | { error: FetchBaseQueryError }> => {
try {
const members = await client.request<Record<string, any>[]>(
readItems('members', {
readItems('members_v2', {
fields: [
'*',
'department.*',
'department.translations.*',
'team.*',
'team.translations.*',
'translations.*',
'roles.id',
'roles.team.*',
'roles.team.translations.*',
'roles.department.*',
'roles.department.translations.*',
'roles.translations.*',
'logo.*',
'portrait.id',
'portrait.title',
],
limit: 500,
}),
);

return { data: members as Member[] };
} catch (error: any) {
return {
Expand Down
Loading