From 5f7e1b6033a0012565fd82d6aed45551a06c7b00 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 18 Aug 2026 07:34:32 +0200 Subject: [PATCH] feat(overview): enhance certificate status display with current and minimum values --- backend/services/falukantService.js | 6 ++ frontend/src/i18n/locales/ceb/falukant.json | 5 ++ frontend/src/i18n/locales/de/falukant.json | 10 ++++ frontend/src/i18n/locales/en/falukant.json | 5 ++ frontend/src/i18n/locales/es/falukant.json | 5 ++ frontend/src/i18n/locales/fr/falukant.json | 5 ++ frontend/src/views/falukant/OverviewView.vue | 59 +++++++++++++++++++- 7 files changed, 94 insertions(+), 1 deletion(-) diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index f1244f5..11bc91f 100755 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3096,6 +3096,9 @@ class FalukantService extends BaseService { const highestPoliticalOfficeRank = Number(highestPoliticalOffice?.rank || 0); const highestChurchOfficeRank = Number(highestChurchOffice?.rank || 0); const highestOfficeRank = Math.max(highestPoliticalOfficeRank, highestChurchOfficeRank); + const highestOfficeName = highestPoliticalOfficeRank >= highestChurchOfficeRank + ? highestPoliticalOffice?.name ?? null + : highestChurchOffice?.name ?? null; const nobilityLevel = Number(title?.level || 0); const knowledgePoints = getKnowledgePoints(avgKnowledge); @@ -3129,9 +3132,12 @@ class FalukantService extends BaseService { highestPoliticalOfficeName: highestPoliticalOffice?.name ?? null, highestChurchOfficeName: highestChurchOffice?.name ?? null, highestOfficeRank, + highestOfficeName, nobilityLevel, + nobilityTitleLabel: title?.labelTr ?? null, reputation, housePosition, + houseLabel: house?.houseType?.labelTr ?? null, knowledgePoints, productionPoints, officePoints, diff --git a/frontend/src/i18n/locales/ceb/falukant.json b/frontend/src/i18n/locales/ceb/falukant.json index 18c3572..ed9e1fe 100755 --- a/frontend/src/i18n/locales/ceb/falukant.json +++ b/frontend/src/i18n/locales/ceb/falukant.json @@ -231,6 +231,11 @@ "statusMode": { "one_of": "At least one status condition", "two_of": "At least two status conditions" + }, + "statusValue": { + "currentAndMinimum": "{current} (minimum: {minimum})", + "office": { "none": "walay katungdanan", "minimum": "katungdanan nga ranggo {rank} o mas taas" }, + "house": { "none": "walay balay" } } }, "summary": { diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index 604cef9..3aa0272 100755 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -215,6 +215,16 @@ "statusMode": { "one_of": "Mindestens eine Statusbedingung", "two_of": "Mindestens zwei Statusbedingungen" + }, + "statusValue": { + "currentAndMinimum": "{current} (mindestens: {minimum})", + "office": { + "none": "kein Amt", + "minimum": "ein Amt ab Rang {rank}" + }, + "house": { + "none": "kein Haus" + } } }, "summary": { diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index 2302a19..ff5e23c 100755 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -221,6 +221,11 @@ "statusMode": { "one_of": "At least one status condition", "two_of": "At least two status conditions" + }, + "statusValue": { + "currentAndMinimum": "{current} (minimum: {minimum})", + "office": { "none": "no office", "minimum": "an office of rank {rank} or higher" }, + "house": { "none": "no house" } } }, "summary": { diff --git a/frontend/src/i18n/locales/es/falukant.json b/frontend/src/i18n/locales/es/falukant.json index 6c2be2d..7f8c8e0 100755 --- a/frontend/src/i18n/locales/es/falukant.json +++ b/frontend/src/i18n/locales/es/falukant.json @@ -214,6 +214,11 @@ "statusMode": { "one_of": "Al menos una condición de estatus", "two_of": "Al menos dos condiciones de estatus" + }, + "statusValue": { + "currentAndMinimum": "{current} (mínimo: {minimum})", + "office": { "none": "sin cargo", "minimum": "un cargo de rango {rank} o superior" }, + "house": { "none": "sin casa" } } }, "summary": { diff --git a/frontend/src/i18n/locales/fr/falukant.json b/frontend/src/i18n/locales/fr/falukant.json index deae090..c4e6e0e 100755 --- a/frontend/src/i18n/locales/fr/falukant.json +++ b/frontend/src/i18n/locales/fr/falukant.json @@ -214,6 +214,11 @@ "statusMode": { "one_of": "Au moins une condition de statut", "two_of": "Au moins deux conditions de statut" + }, + "statusValue": { + "currentAndMinimum": "{current} (minimum : {minimum})", + "office": { "none": "aucune fonction", "minimum": "une fonction de rang {rank} ou supérieur" }, + "house": { "none": "aucune maison" } } }, "summary": { diff --git a/frontend/src/views/falukant/OverviewView.vue b/frontend/src/views/falukant/OverviewView.vue index cf01173..4c0dcda 100755 --- a/frontend/src/views/falukant/OverviewView.vue +++ b/frontend/src/views/falukant/OverviewView.vue @@ -204,7 +204,7 @@ :class="{ 'is-met': option.met }" > {{ certificateRequirementLabel(option.type) }}: - {{ formatCertificateRequirement(option.current, option.required) }} + {{ certificateStatusOptionLabel(option) }} @@ -796,6 +796,63 @@ export default { certificateStatusRequirementLabel(mode) { return this.$t(`falukant.overview.certificate.statusMode.${mode}`); }, + certificateStatusOptionLabel(option) { + return this.$t('falukant.overview.certificate.statusValue.currentAndMinimum', { + current: this.certificateStatusValueLabel(option.type, option.current), + minimum: this.certificateMinimumStatusValueLabel(option.type, option.required), + }); + }, + certificateStatusValueLabel(type, value) { + const currentValues = this.certificateProgress?.currentValues || {}; + if (type === 'officePoints') { + const officeName = currentValues.highestOfficeName; + if (officeName) { + const politicalKey = `falukant.politics.offices.${officeName}`; + const churchKey = `falukant.church.offices.${officeName}`; + if (this.$te(politicalKey)) return this.$t(politicalKey); + if (this.$te(churchKey)) return this.$t(churchKey); + return officeName; + } + return this.$t('falukant.overview.certificate.statusValue.office.none'); + } + if (type === 'nobilityPoints') { + const title = currentValues.nobilityTitleLabel; + if (title) { + const gender = this.falukantUser?.character?.gender || 'male'; + const key = `falukant.titles.${gender}.${title}`; + return this.$te(key) ? this.$t(key) : title; + } + } + if (type === 'housePoints') { + return this.certificateHouseStatusLabel(currentValues.housePosition, currentValues.houseLabel); + } + return this.formatCertificateValue(value); + }, + certificateMinimumStatusValueLabel(type, required) { + if (type === 'officePoints') { + return this.$t('falukant.overview.certificate.statusValue.office.minimum', { rank: required }); + } + if (type === 'nobilityPoints') { + const gender = this.falukantUser?.character?.gender || 'male'; + const titleLevels = ['noncivil', 'civil', 'sir', 'townlord', 'by', 'landlord']; + const title = titleLevels[Number(required)] || null; + const key = title ? `falukant.titles.${gender}.${title}` : null; + return key && this.$te(key) ? this.$t(key) : this.formatCertificateValue(required); + } + if (type === 'housePoints') { + const minimumPositionByPoints = { 1: 2, 2: 4, 3: 6, 4: 8, 5: 10 }; + return this.certificateHouseStatusLabel(minimumPositionByPoints[Number(required)] || 0); + } + return this.formatCertificateValue(required); + }, + certificateHouseStatusLabel(position, fallbackLabel = null) { + const value = Number(position || 0); + if (!value) return this.$t('falukant.overview.certificate.statusValue.house.none'); + const key = `falukant.nobility.advance.housePosition.${value}`; + return this.$te(key) + ? this.$t(key) + : (fallbackLabel || this.$t('falukant.nobility.advance.housePosition.fallback', { level: value })); + }, async fetchPotentialHeirs() { this.loadingHeirs = true; try {