diff --git a/frontend/src/pages/QuestPage.tsx b/frontend/src/pages/QuestPage.tsx index 8acab72..0135291 100644 --- a/frontend/src/pages/QuestPage.tsx +++ b/frontend/src/pages/QuestPage.tsx @@ -214,25 +214,37 @@ export function QuestPage() { if (loadActive || loadAvail) return
Chargement…
; - // Séparer quêtes narratives (slots limités) et répétables (toujours en fond) - const activeStory = active?.filter((pq: any) => !pq.quest.repeatable) ?? []; - const activeDaily = active?.filter((pq: any) => pq.quest.repeatable) ?? []; - const availableStory = available?.filter((q: any) => !q.repeatable) ?? []; - const availableDaily = available?.filter((q: any) => q.repeatable) ?? []; + const isCraftQuest = (q: any) => ['forge_item', 'craft_item'].includes(q.objectiveType ?? q.quest?.objectiveType); + const isCombatQuest = (q: any) => !isCraftQuest(q); + + // Split by category + const activeAll = active ?? []; + const activeCombat = activeAll.filter((pq: any) => !pq.quest.repeatable && isCombatQuest(pq)); + const activeCraft = activeAll.filter((pq: any) => !pq.quest.repeatable && isCraftQuest(pq)); + const activeDaily = activeAll.filter((pq: any) => pq.quest.repeatable); + + const availableAll = available ?? []; + const availableCombat = availableAll.filter((q: any) => !q.repeatable && isCombatQuest(q)); + const availableCraft = availableAll.filter((q: any) => !q.repeatable && isCraftQuest(q)); + const availableDaily = availableAll.filter((q: any) => q.repeatable); + + // Stagger: show max 3 combat quests at a time + const shownCombat = availableCombat.slice(0, 3); + const hiddenCount = availableCombat.length - shownCombat.length; return (

📜 Quêtes

- {/* Active story quests */} + {/* Active combat quests */}

- Quêtes actives ({activeStory.length}/3) + Quêtes actives ({activeCombat.length}/3)

- {activeStory.length > 0 ? ( + {activeCombat.length > 0 ? (
- {activeStory.map((pq: any) => )} + {activeCombat.map((pq: any) => )}
) : (
@@ -241,23 +253,41 @@ export function QuestPage() { )}
- {/* Available story quests */} + {/* Available combat quests (staggered) */}

- Quêtes disponibles + Quêtes de combat

- {availableStory.length > 0 ? ( + {shownCombat.length > 0 ? (
- {availableStory.map((q: any) => )} + {shownCombat.map((q: any) => )} + {hiddenCount > 0 && ( +
+ +{hiddenCount} quête{hiddenCount > 1 ? 's' : ''} supplémentaire{hiddenCount > 1 ? 's' : ''} après celles-ci +
+ )}
) : (
- Toutes les quêtes sont acceptées ou complétées + Toutes les quêtes de combat sont complétées
)}
+ {/* Métiers (craft/forge — hors pool, comme les dailies) */} + {(activeCraft.length > 0 || availableCraft.length > 0) && ( +
+

+ 🔨 Métiers +

+
+ {activeCraft.map((pq: any) => )} + {availableCraft.map((q: any) => )} +
+
+ )} + {/* Tâches quotidiennes (répétables — toujours en fond) */}

diff --git a/src/quest/quest.service.ts b/src/quest/quest.service.ts index 232c9e2..03fd48f 100644 --- a/src/quest/quest.service.ts +++ b/src/quest/quest.service.ts @@ -92,17 +92,20 @@ export class QuestService { throw new BadRequestException(`Niveau ${quest.minLevel} requis`); } - // Check active quest count (repeatable quests don't count toward the limit) - if (!quest.repeatable) { - const activeNonRepeatable = await this.playerQuestRepo + // Check active quest count + // Repeatable + craft/forge quests don't count toward the 3-slot limit + const isCraftQuest = ['forge_item', 'craft_item'].includes(quest.objectiveType); + if (!quest.repeatable && !isCraftQuest) { + const activeCombat = await this.playerQuestRepo .createQueryBuilder('pq') .innerJoin('pq.quest', 'q') .where('pq.character_id = :characterId', { characterId }) .andWhere('pq.status = :status', { status: 'active' }) .andWhere('q.repeatable = false') + .andWhere('q.objective_type NOT IN (:...types)', { types: ['forge_item', 'craft_item'] }) .getCount(); - if (activeNonRepeatable >= MAX_ACTIVE_QUESTS) { - throw new BadRequestException(`Maximum ${MAX_ACTIVE_QUESTS} quêtes actives (hors répétables)`); + if (activeCombat >= MAX_ACTIVE_QUESTS) { + throw new BadRequestException(`Maximum ${MAX_ACTIVE_QUESTS} quêtes de combat actives`); } }