Implement cooldown feature for nobility advancement

- Added logic in FalukantService to calculate the next available advancement date based on the user's last advancement.
- Updated the frontend to display a cooldown message indicating when the user can next advance in nobility.
- Enhanced the NobilityView component to handle and format the next advancement date appropriately.
This commit is contained in:
Torsten Schulz (local)
2025-11-26 17:23:54 +01:00
parent c1b69389c6
commit 608e62c2bd
4 changed files with 28 additions and 4 deletions

View File

@@ -2907,6 +2907,13 @@ class FalukantService extends BaseService {
], ],
attributes: ['labelTr', 'level'] attributes: ['labelTr', 'level']
}); });
let nextAdvanceAt = null;
if (falukantUser.lastNobilityAdvanceAt) {
const last = new Date(falukantUser.lastNobilityAdvanceAt);
const next = new Date(last.getTime());
next.setDate(next.getDate() + 7);
nextAdvanceAt = next.toISOString();
}
const currentTitleLevel = nobility.level; const currentTitleLevel = nobility.level;
const nextTitle = await TitleOfNobility.findOne({ const nextTitle = await TitleOfNobility.findOne({
where: { where: {
@@ -2922,7 +2929,8 @@ class FalukantService extends BaseService {
}); });
return { return {
current: nobility, current: nobility,
next: nextTitle next: nextTitle,
nextAdvanceAt
}; };
} }

View File

@@ -538,7 +538,8 @@
}, },
"advance": { "advance": {
"confirm": "Aufsteigen beantragen" "confirm": "Aufsteigen beantragen"
} },
"cooldown": "Du kannst frühestens wieder am {date} aufsteigen."
}, },
"reputation": { "reputation": {
"title": "Reputation", "title": "Reputation",

View File

@@ -41,6 +41,9 @@
"raft": "Raft", "raft": "Raft",
"sailing_ship": "Sailing ship" "sailing_ship": "Sailing ship"
} }
},
"nobility": {
"cooldown": "You can only advance again on {date}."
} }
} }
} }

View File

@@ -23,6 +23,9 @@
{{ $t('falukant.nobility.nextTitle') }}: {{ $t('falukant.nobility.nextTitle') }}:
<strong>{{ $t(`falukant.titles.${gender}.${next.labelTr}`) }}</strong> <strong>{{ $t(`falukant.titles.${gender}.${next.labelTr}`) }}</strong>
</p> </p>
<p v-if="nextAdvanceAt && !canAdvance">
{{ $t('falukant.nobility.cooldown', { date: formatDate(nextAdvanceAt) }) }}
</p>
<ul class="prerequisites"> <ul class="prerequisites">
<li v-for="req in next.requirements" :key="req.titleId"> <li v-for="req in next.requirements" :key="req.titleId">
{{ $t(`falukant.nobility.requirement.${req.requirementType}`, { amount: formatCost(req.requirementValue) }) }} {{ $t(`falukant.nobility.requirement.${req.requirementType}`, { amount: formatCost(req.requirementValue) }) }}
@@ -32,7 +35,6 @@
<span v-if="!isAdvancing">{{ $t('falukant.nobility.advance.confirm') }}</span> <span v-if="!isAdvancing">{{ $t('falukant.nobility.advance.confirm') }}</span>
<span v-else>{{ $t('falukant.nobility.advance.processing') }}</span> <span v-else>{{ $t('falukant.nobility.advance.processing') }}</span>
</button> </button>
<!-- debug state output removed -->
</div> </div>
</div> </div>
@@ -58,6 +60,7 @@
], ],
current: { labelTr: '', requirements: [], charactersWithNobleTitle: [] }, current: { labelTr: '', requirements: [], charactersWithNobleTitle: [] },
next: { labelTr: '', requirements: [] }, next: { labelTr: '', requirements: [] },
nextAdvanceAt: null,
isAdvancing: false isAdvancing: false
}; };
}, },
@@ -67,7 +70,11 @@
return this.current.charactersWithNobleTitle[0]?.gender || 'male'; return this.current.charactersWithNobleTitle[0]?.gender || 'male';
}, },
canAdvance() { canAdvance() {
return true; if (!this.next) return false;
if (!this.nextAdvanceAt) return true;
const now = new Date();
const nextDate = new Date(this.nextAdvanceAt);
return nextDate <= now;
} }
}, },
async mounted() { async mounted() {
@@ -101,6 +108,7 @@
const { data } = await apiClient.get('/api/falukant/nobility'); const { data } = await apiClient.get('/api/falukant/nobility');
this.current = data.current; this.current = data.current;
this.next = data.next; this.next = data.next;
this.nextAdvanceAt = data.nextAdvanceAt || null;
} catch (err) { } catch (err) {
console.error('Error loading nobility:', err); console.error('Error loading nobility:', err);
} }
@@ -124,6 +132,10 @@
}, },
formatCost(val) { formatCost(val) {
return new Intl.NumberFormat(navigator.language, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(val); return new Intl.NumberFormat(navigator.language, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(val);
},
formatDate(isoString) {
const d = new Date(isoString);
return d.toLocaleDateString();
} }
} }
}; };