From 955ea1a9edb545221e149ec763bded444cb30761 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 26 Jan 2026 16:45:13 +0100 Subject: [PATCH] Enhance gift sending logic: Implement retry mechanism for 'tooOften' error in FalukantService and update error handling in FamilyView to display retry time. --- backend/controllers/falukantController.js | 11 ++++++++++- backend/services/falukantService.js | 5 ++++- frontend/src/i18n/locales/de/falukant.json | 3 ++- frontend/src/i18n/locales/en/falukant.json | 2 +- frontend/src/views/falukant/FamilyView.vue | 14 ++++++++++++-- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/backend/controllers/falukantController.js b/backend/controllers/falukantController.js index 848b726..a2d3e7d 100644 --- a/backend/controllers/falukantController.js +++ b/backend/controllers/falukantController.js @@ -99,7 +99,16 @@ class FalukantController { return this.service.getGifts(userId); }); this.getChildren = this._wrapWithUser((userId) => this.service.getChildren(userId)); - this.sendGift = this._wrapWithUser((userId, req) => this.service.sendGift(userId, req.body.giftId)); + this.sendGift = this._wrapWithUser(async (userId, req) => { + try { + return await this.service.sendGift(userId, req.body.giftId); + } catch (e) { + if (e && e.name === 'PreconditionError' && e.message === 'tooOften') { + throw { status: 412, message: 'tooOften', retryAt: e.meta?.retryAt }; + } + throw e; + } + }); this.getTitlesOfNobility = this._wrapWithUser((userId) => this.service.getTitlesOfNobility(userId)); this.getHouseTypes = this._wrapWithUser((userId) => this.service.getHouseTypes(userId)); diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 5c9351b..7ba69fd 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -2868,7 +2868,10 @@ class FalukantService extends BaseService { limit: 1 }); if (lastGift && (lastGift.createdAt.getTime() + 3_600_000) > Date.now()) { - throw new PreconditionError('tooOften'); + const retryAt = new Date(lastGift.createdAt.getTime() + 3_600_000); + const err = new PreconditionError('tooOften'); + err.meta = { retryAt: retryAt.toISOString() }; + throw err; } const gift = await PromotionalGift.findOne({ where: { id: giftId }, diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index e6d532a..e1e3ca7 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -522,7 +522,8 @@ "tooOften": "Du kannst nicht so oft Geschenke machen.", "insufficientFunds": "Du hast nicht genug Geld." }, - "success": "Das Geschenk wurde überreicht." + "success": "Das Geschenk wurde überreicht.", + "nextGiftAt": "Nächstes Geschenk ab" } }, "product": { diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index fd7ed8f..9d35108 100644 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -197,7 +197,7 @@ }, "nobility": { "cooldown": "You can only advance again on {date}." - }, + }, "branchProduction": { "storageAvailable": "Free storage" }, diff --git a/frontend/src/views/falukant/FamilyView.vue b/frontend/src/views/falukant/FamilyView.vue index fb0c519..459bab1 100644 --- a/frontend/src/views/falukant/FamilyView.vue +++ b/frontend/src/views/falukant/FamilyView.vue @@ -353,8 +353,18 @@ export default { this.$root.$refs.messageDialog.open('tr:falukant.family.sendgift.success'); } catch (error) { console.log(error.response); - if (error.response.status === 412) { - this.$root.$refs.errorDialog.open(`tr:falukant.family.sendgift.error.${error.response.data.error}`); + if (error.response?.status === 412) { + const retryAtIso = error.response?.data?.retryAt; + if (retryAtIso) { + const retryStr = new Date(retryAtIso).toLocaleString(navigator.language, { + year: 'numeric', month: '2-digit', day: '2-digit', + hour: '2-digit', minute: '2-digit' + }); + const baseMsg = this.$t(`falukant.family.sendgift.error.${error.response.data.error}`); + this.$root.$refs.errorDialog.open(`${baseMsg} — ${this.$t('falukant.family.sendgift.nextGiftAt')}: ${retryStr}`); + } else { + this.$root.$refs.errorDialog.open(`tr:falukant.family.sendgift.error.${error.response.data.error}`); + } } else { this.$root.$refs.errorDialog.open(`tr:falukant.family.sendgift.error.generic`); }