Implement church career information retrieval and update related components: Add a new method in FalukantService to fetch church career details for characters, including current and approved office levels. Enhance DashboardWidget, StatusBar, and ChurchView components to handle new church-related socket events and display relevant information. Update localization files for church-related terms and error messages in English, German, and Spanish.
This commit is contained in:
@@ -6965,6 +6965,66 @@ ORDER BY r.id`,
|
||||
}
|
||||
}
|
||||
|
||||
async getChurchCareerInfo(characterId) {
|
||||
const [currentOffices, approvedApplications] = await Promise.all([
|
||||
ChurchOffice.findAll({
|
||||
where: { characterId },
|
||||
include: [{
|
||||
model: ChurchOfficeType,
|
||||
as: 'type',
|
||||
attributes: ['id', 'name', 'hierarchyLevel']
|
||||
}]
|
||||
}),
|
||||
ChurchApplication.findAll({
|
||||
where: {
|
||||
characterId,
|
||||
status: 'approved'
|
||||
},
|
||||
include: [{
|
||||
model: ChurchOfficeType,
|
||||
as: 'officeType',
|
||||
attributes: ['id', 'name', 'hierarchyLevel']
|
||||
}]
|
||||
})
|
||||
]);
|
||||
|
||||
const currentLevels = currentOffices.map((office) => Number(office.type?.hierarchyLevel ?? -1));
|
||||
const approvedLevels = approvedApplications.map((application) => Number(application.officeType?.hierarchyLevel ?? -1));
|
||||
const highestCurrentLevel = currentLevels.length ? Math.max(...currentLevels) : -1;
|
||||
const highestEverLevel = [...currentLevels, ...approvedLevels].length
|
||||
? Math.max(...currentLevels, ...approvedLevels)
|
||||
: -1;
|
||||
|
||||
const currentHighest = currentOffices
|
||||
.map((office) => office.type)
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => Number(b.hierarchyLevel || 0) - Number(a.hierarchyLevel || 0))[0] || null;
|
||||
|
||||
const allAttained = [
|
||||
...currentOffices.map((office) => office.type),
|
||||
...approvedApplications.map((application) => application.officeType)
|
||||
]
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => Number(b.hierarchyLevel || 0) - Number(a.hierarchyLevel || 0));
|
||||
|
||||
const highestEver = allAttained[0] || null;
|
||||
|
||||
return {
|
||||
highestCurrentLevel,
|
||||
highestEverLevel,
|
||||
highestCurrentOffice: currentHighest ? {
|
||||
id: currentHighest.id,
|
||||
name: currentHighest.name,
|
||||
hierarchyLevel: currentHighest.hierarchyLevel
|
||||
} : null,
|
||||
highestEverOffice: highestEver ? {
|
||||
id: highestEver.id,
|
||||
name: highestEver.name,
|
||||
hierarchyLevel: highestEver.hierarchyLevel
|
||||
} : null
|
||||
};
|
||||
}
|
||||
|
||||
async getAvailableChurchPositions(hashedUserId) {
|
||||
const user = await getFalukantUserOrFail(hashedUserId);
|
||||
const character = await FalukantCharacter.findOne({
|
||||
@@ -6975,6 +7035,8 @@ ORDER BY r.id`,
|
||||
return [];
|
||||
}
|
||||
|
||||
const churchCareer = await this.getChurchCareerInfo(character.id);
|
||||
|
||||
// Prüfe welche Kirchenämter der Charakter bereits innehat
|
||||
const heldOffices = await ChurchOffice.findAll({
|
||||
where: { characterId: character.id },
|
||||
@@ -7029,7 +7091,8 @@ ORDER BY r.id`,
|
||||
const availablePositions = [];
|
||||
|
||||
for (const officeType of officeTypes) {
|
||||
// Prüfe Voraussetzungen: Hat der User bereits das erforderliche niedrigere Amt?
|
||||
// Prüfe Voraussetzungen: Maßgeblich ist die höchste bisherige Kirchenlaufbahn,
|
||||
// nicht nur das aktuell gehaltene Amt.
|
||||
const requirement = officeType.requirements?.[0];
|
||||
|
||||
console.log(`[getAvailableChurchPositions] Checking ${officeType.name} (id=${officeType.id}, hierarchyLevel=${officeType.hierarchyLevel}):`, {
|
||||
@@ -7043,9 +7106,12 @@ ORDER BY r.id`,
|
||||
// Wenn eine Voraussetzung definiert ist
|
||||
const prerequisiteId = requirement.prerequisiteOfficeTypeId;
|
||||
if (prerequisiteId !== null && prerequisiteId !== undefined) {
|
||||
// Prüfe ob der User das erforderliche Amt innehat
|
||||
if (!heldOfficeTypeIds.includes(prerequisiteId)) {
|
||||
console.log(`[getAvailableChurchPositions] Skipping ${officeType.name}: User doesn't have prerequisite office ${prerequisiteId}. Held offices:`, heldOfficeTypeIds);
|
||||
const prerequisiteOffice = await ChurchOfficeType.findByPk(prerequisiteId, {
|
||||
attributes: ['id', 'hierarchyLevel']
|
||||
});
|
||||
const requiredLevel = Number(prerequisiteOffice?.hierarchyLevel ?? (officeType.hierarchyLevel - 1));
|
||||
if (churchCareer.highestEverLevel < requiredLevel) {
|
||||
console.log(`[getAvailableChurchPositions] Skipping ${officeType.name}: User career too low for prerequisite level ${requiredLevel}. Highest ever:`, churchCareer.highestEverLevel);
|
||||
continue; // Voraussetzung nicht erfüllt - User hat das erforderliche Amt nicht
|
||||
}
|
||||
}
|
||||
@@ -7113,6 +7179,7 @@ ORDER BY r.id`,
|
||||
if (availableSeats > 0) {
|
||||
// Finde den Supervisor (höheres Amt in derselben Region oder Eltern-Region)
|
||||
let supervisor = null;
|
||||
let decisionMode = officeType.hierarchyLevel === 0 ? 'entry' : 'interim';
|
||||
const higherOfficeTypeIds = await ChurchOfficeType.findAll({
|
||||
where: {
|
||||
hierarchyLevel: { [Op.gt]: officeType.hierarchyLevel }
|
||||
@@ -7135,7 +7202,21 @@ ORDER BY r.id`,
|
||||
{
|
||||
model: FalukantCharacter,
|
||||
as: 'holder',
|
||||
attributes: ['id']
|
||||
attributes: ['id', 'userId'],
|
||||
include: [
|
||||
{
|
||||
model: FalukantPredefineFirstname,
|
||||
as: 'definedFirstName',
|
||||
attributes: ['name'],
|
||||
required: false
|
||||
},
|
||||
{
|
||||
model: FalukantPredefineLastname,
|
||||
as: 'definedLastName',
|
||||
attributes: ['name'],
|
||||
required: false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
order: [
|
||||
@@ -7147,8 +7228,10 @@ ORDER BY r.id`,
|
||||
if (supervisorOffice && supervisorOffice.holder) {
|
||||
supervisor = {
|
||||
id: supervisorOffice.holder.id,
|
||||
name: 'Supervisor' // Wird später geladen falls nötig
|
||||
name: `${supervisorOffice.holder.definedFirstName?.name || ''} ${supervisorOffice.holder.definedLastName?.name || ''}`.trim() || 'Supervisor',
|
||||
controlledBy: supervisorOffice.holder.userId ? 'player' : 'npc'
|
||||
};
|
||||
decisionMode = supervisor.controlledBy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7163,7 +7246,8 @@ ORDER BY r.id`,
|
||||
},
|
||||
regionId: region.id,
|
||||
availableSeats: availableSeats,
|
||||
supervisor: supervisor
|
||||
supervisor: supervisor,
|
||||
decisionMode
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7280,13 +7364,31 @@ ORDER BY r.id`,
|
||||
attributes: ['id', 'regionId']
|
||||
});
|
||||
if (!character) {
|
||||
throw new Error('Character not found');
|
||||
throw new Error('falukant.church.available.errors.characterNotFound');
|
||||
}
|
||||
|
||||
const churchCareer = await this.getChurchCareerInfo(character.id);
|
||||
|
||||
// Prüfe ob Position verfügbar ist
|
||||
const officeType = await ChurchOfficeType.findByPk(officeTypeId);
|
||||
if (!officeType) {
|
||||
throw new Error('Office type not found');
|
||||
throw new Error('falukant.church.available.errors.officeTypeNotFound');
|
||||
}
|
||||
|
||||
const requirement = await ChurchOfficeRequirement.findOne({
|
||||
where: { officeTypeId },
|
||||
attributes: ['prerequisiteOfficeTypeId']
|
||||
});
|
||||
if (requirement?.prerequisiteOfficeTypeId) {
|
||||
const prerequisiteOffice = await ChurchOfficeType.findByPk(requirement.prerequisiteOfficeTypeId, {
|
||||
attributes: ['hierarchyLevel']
|
||||
});
|
||||
const requiredLevel = Number(prerequisiteOffice?.hierarchyLevel ?? (officeType.hierarchyLevel - 1));
|
||||
if (churchCareer.highestEverLevel < requiredLevel) {
|
||||
throw new Error('falukant.church.available.errors.churchCareerTooLow');
|
||||
}
|
||||
} else if (officeType.hierarchyLevel > 0 && churchCareer.highestEverLevel < officeType.hierarchyLevel - 1) {
|
||||
throw new Error('falukant.church.available.errors.churchCareerTooLow');
|
||||
}
|
||||
|
||||
const occupiedCount = await ChurchOffice.count({
|
||||
@@ -7297,7 +7399,7 @@ ORDER BY r.id`,
|
||||
});
|
||||
|
||||
if (occupiedCount >= officeType.seatsPerRegion) {
|
||||
throw new Error('No available seats');
|
||||
throw new Error('falukant.church.available.errors.noAvailableSeats');
|
||||
}
|
||||
|
||||
// Finde Supervisor (nur wenn es nicht die niedrigste Position ist)
|
||||
@@ -7334,16 +7436,13 @@ ORDER BY r.id`,
|
||||
limit: 1
|
||||
});
|
||||
|
||||
if (!supervisorOffice) {
|
||||
throw new Error('No supervisor position exists in this region. Higher church offices must be filled before you can apply.');
|
||||
if (supervisorOffice?.holder) {
|
||||
supervisorId = supervisorOffice.holder.id;
|
||||
} else {
|
||||
supervisorId = null;
|
||||
}
|
||||
if (!supervisorOffice.holder) {
|
||||
const officeName = supervisorOffice.type?.name || 'higher';
|
||||
throw new Error(`The ${officeName} position in this region is vacant. It must be filled before you can apply.`);
|
||||
}
|
||||
supervisorId = supervisorOffice.holder.id;
|
||||
} else {
|
||||
throw new Error('No supervisor office type found');
|
||||
supervisorId = null;
|
||||
}
|
||||
}
|
||||
// Für Einstiegspositionen (hierarchyLevel 0) ist kein Supervisor erforderlich
|
||||
@@ -7359,7 +7458,7 @@ ORDER BY r.id`,
|
||||
});
|
||||
|
||||
if (existingApplication) {
|
||||
throw new Error('Application already exists');
|
||||
throw new Error('falukant.church.available.errors.applicationAlreadyExists');
|
||||
}
|
||||
|
||||
// Erstelle Bewerbung
|
||||
|
||||
Reference in New Issue
Block a user