services_ChoreoService.js
import { debug } from "@/utils/logging";
import ax from "./RequestService";
import i18n from "@/plugins/vue-i18n";
/**
* Service for managing choreographies, participants, and positions.
*
* @class ChoreoService
*/
class ChoreoService {
/**
* Get mat type options for choreography creation.
* @returns {Array} Array of mat type option objects
*/
matTypeOptions = () => [
{
label: i18n.t("matTypeOptions.by-sport"),
options: [
{ value: "cheer", text: i18n.t("matTypeOptions.descriptions.cheer") },
],
},
{
label: i18n.t("matTypeOptions.by-stage"),
options: [
{ value: "square", text: i18n.t("matTypeOptions.descriptions.square") },
{ value: "1:2", text: i18n.t("matTypeOptions.descriptions.1-2") },
{ value: "3:4", text: i18n.t("matTypeOptions.descriptions.3-4") },
],
},
];
/**
* Get all choreographies for a team.
* @param {string} teamId - ID of the team
* @returns {Promise<Array>} Array of choreographies
*/
getByTeam(teamId) {
debug("Querying choreos with teamId", teamId);
return ax.get("/choreo", { params: { teamId } }).then((res) => {
debug("Successfully queried team");
return res.data;
});
}
/**
* Get a choreography by its ID.
* @param {string} choreoId - ID of the choreography
* @returns {Promise<Object>} Choreography object
*/
getById(choreoId) {
debug("Querying choreo by id", choreoId);
return ax.get(`/choreo/${choreoId}`).then((res) => {
debug("Successfully queried choreo");
return res.data;
});
}
/**
* Change the name of a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} name - New name for the choreography
* @returns {Promise<Object>} Updated choreography
*/
changeName(choreoId, name) {
debug(`Changing the name of choreo ${choreoId} to ${name}`);
return ax.put(`/choreo/${choreoId}`, { name }).then((res) => {
debug("Successfully changed the name of the choreo", name);
return res.data;
});
}
/**
* Change the length (counts) of a choreography.
* @param {string} choreoId - ID of the choreography
* @param {number} counts - New length in counts
* @returns {Promise<Object>} Updated choreography
*/
changeLength(choreoId, counts) {
debug(`Changing the length of choreo ${choreoId} to ${counts}`);
return ax.put(`/choreo/${choreoId}`, { counts }).then((res) => {
debug("Successfully changed the length of choreo", choreoId);
return res.data;
});
}
/**
* Change the mat type of a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} matType - New mat type
* @returns {Promise<Object>} Updated choreography
*/
changeMatType(choreoId, matType) {
debug(`Changing the mat type of choreo ${choreoId} to ${matType}`);
return ax.put(`/choreo/${choreoId}`, { matType }).then((res) => {
debug("Successfully changed the mat type of choreo", choreoId);
return res.data;
});
}
/**
* Add a participant to a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} MemberId - ID of the member to add
* @param {string} color - Color for the participant
* @returns {Promise<Object>} Added participant
*/
addParticipant(choreoId, MemberId, color) {
debug(
`Adding participant ${MemberId} to choreo ${choreoId} with color ${color}`
);
return ax
.post(`/choreo/${choreoId}/participants`, { MemberId, color })
.then((res) => {
debug("Successfully added participant to choreo");
return res.data;
});
}
/**
* Remove a participant from a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} MemberId - ID of the member to remove
* @returns {Promise}
*/
removeParticipant(choreoId, MemberId) {
debug(`Removing participant ${MemberId} from choreo ${choreoId}`);
return ax.delete(`/choreo/${choreoId}/participants/${MemberId}`);
}
/**
* Replace a participant in a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} memberToRemoveId - ID of the member to remove
* @param {string} memberToAddId - ID of the member to add
* @returns {Promise<Object>} Updated participant list
*/
replaceParticipant(choreoId, memberToRemoveId, memberToAddId) {
debug(
`Replacing participant ${memberToRemoveId} for ${memberToAddId} in choreo ${choreoId}`
);
return ax
.patch(`/choreo/${choreoId}/participants`, {
memberToRemoveId,
memberToAddId,
})
.then((res) => {
debug("Successfully replaced participant");
return res.data;
});
}
/**
* Change the color of a participant in a choreography.
* @param {string} choreoId - ID of the choreography
* @param {string} participantId - ID of the participant
* @param {string} color - New color for the participant
* @returns {Promise<Object>} Updated participant
*/
changeParticipantColor(choreoId, participantId, color) {
debug(`Changing participant color with`, {
choreoId,
participantId,
color,
});
return ax
.patch(`/choreo/${choreoId}/participants/${participantId}`, { color })
.then((res) => {
debug("Successfully changed participant color");
return res.data;
});
}
/**
* Create a new choreography.
* @param {string} name - Name of the choreography
* @param {number} counts - Length of the choreography in counts
* @param {string} matType - Mat type for the choreography
* @param {string} seasonTeamId - ID of the season team
* @param {Array} participants - Array of participant objects
* @returns {Promise<Object>} Created choreography
*/
create(name, counts, matType, seasonTeamId, participants) {
debug("Creating choreo", {
name,
counts,
matType,
seasonTeamId,
participants,
});
return ax
.post("/choreo", { name, counts, matType, seasonTeamId, participants })
.then((res) => {
debug("Successfully created choreo");
return res.data;
});
}
/**
* Remove a choreography by its ID.
* @param {string} choreoId - ID of the choreography to remove
* @returns {Promise}
*/
remove(choreoId) {
debug("Deleting choreo", choreoId);
return ax.delete(`/choreo/${choreoId}`).then((res) => {
debug("Successfully deleted choreo");
return res.data;
});
}
/**
* Get positions for all team members for a given count in a choreography.
* @param {Object} choreo - Choreography object
* @param {number} count - Count for which to get positions
* @param {Array} teamMembers - Array of team member objects
* @returns {Array} Array of position objects
*/
getPositionsFromChoreoAndCount(choreo, count, teamMembers) {
if (!teamMembers || !choreo || !choreo.Lineups) return [];
const relevantLineups = choreo.Lineups.filter(
(l) =>
l.Positions &&
l.Positions.length > 0 &&
l.startCount <= count &&
l.endCount >= count
);
const positionsForCurrentCount = relevantLineups
.map((l) => l.Positions)
.flat();
let unPositionedTeamMembers = teamMembers.filter(
(m) => !positionsForCurrentCount.some((p) => p.MemberId == m.id)
);
const interpolatedPositions = [];
unPositionedTeamMembers.forEach((member) => {
const lineupsForMember = choreo.Lineups.filter(
(l) => l.Positions && l.Positions.some((p) => p.MemberId == member.id)
);
const previousLineupForMember = lineupsForMember
.filter((l) => l.endCount < count)
.sort((a, b) => b.endCount - a.endCount)[0];
const followingLineupForMember = lineupsForMember
.filter((l) => l.startCount > count)
.sort((a, b) => a.startCount - b.startCount)[0];
const previousPositionForMember = previousLineupForMember
? previousLineupForMember.Positions.find((p) => p.MemberId == member.id)
: null;
const followingPositionForMember = followingLineupForMember
? followingLineupForMember.Positions.find(
(p) => p.MemberId == member.id
)
: null;
if (!previousPositionForMember && followingPositionForMember)
interpolatedPositions.push(followingPositionForMember);
else if (previousPositionForMember && !followingPositionForMember)
interpolatedPositions.push(previousPositionForMember);
else if (previousPositionForMember && followingPositionForMember) {
const countsSincePrevious = count - previousLineupForMember.endCount;
const countsBetweenPreviousAndFollowing =
followingLineupForMember.startCount -
previousLineupForMember.endCount;
const advancement =
countsSincePrevious / countsBetweenPreviousAndFollowing;
const interpolatedPositionForMember = {
Member: member,
MemberId: member.id,
x:
previousPositionForMember.x +
(followingPositionForMember.x - previousPositionForMember.x) *
advancement,
y:
previousPositionForMember.y +
(followingPositionForMember.y - previousPositionForMember.y) *
advancement,
};
interpolatedPositions.push(interpolatedPositionForMember);
}
});
unPositionedTeamMembers = teamMembers.filter(
(m) =>
![...positionsForCurrentCount, ...interpolatedPositions].some(
(p) => p.MemberId == m.id
)
);
const defaultPositions = unPositionedTeamMembers.map((member, i) => {
let yNew = Math.floor(i / 7) * 10 + 10;
let xNew = (100 / 7) * (i % 7) + 100 / 14;
return {
Member: member,
MemberId: member.id,
x: xNew,
y: yNew,
};
});
return [
...positionsForCurrentCount,
...interpolatedPositions,
...defaultPositions,
]
.map((p) => ({
...p,
Member: teamMembers.find((tm) => tm.id == p.MemberId),
}))
.sort((a, b) => a.Member.name.localeCompare(b.Member.name));
}
}
export default new ChoreoService();