Skip to content

Commit 7b49816

Browse files
committed
assignment failure details
1 parent 8b1a2c8 commit 7b49816

4 files changed

Lines changed: 69 additions & 19 deletions

File tree

src/dashboard/src/features/game/components/GameSettingsPage.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export const GameSettingsPage: React.FC = () => {
2323
const [selectedRole, setSelectedRole] = useState<string>('');
2424
const [updatingRoles, setUpdatingRoles] = useState(false);
2525
const [updatingPlayerCount, setUpdatingPlayerCount] = useState(false);
26+
const [assigningRoles, setAssigningRoles] = useState(false);
2627
const [pendingFields, setPendingFields] = useState<Record<string, boolean>>({});
28+
const [error, setError] = useState<string | null>(null);
2729

2830
const AVAILABLE_ROLES = [
2931
"平民", "狼人", "女巫", "預言家", "獵人",
@@ -136,11 +138,16 @@ export const GameSettingsPage: React.FC = () => {
136138
};
137139

138140
const handleRandomAssign = async () => {
139-
if (!guildId) return;
141+
if (!guildId || assigningRoles) return;
142+
setError(null);
143+
setAssigningRoles(true);
140144
try {
141145
await api.assignRoles(guildId);
142146
} catch (error: any) {
143147
console.error("Assign failed", error);
148+
setError(error.message || t('errors.assignFailed'));
149+
} finally {
150+
setAssigningRoles(false);
144151
}
145152
};
146153

@@ -327,13 +334,32 @@ export const GameSettingsPage: React.FC = () => {
327334
</div>
328335
<button
329336
onClick={handleRandomAssign}
330-
className="text-xs flex items-center gap-1.5 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-400 px-3 py-1.5 rounded-full hover:bg-indigo-200 dark:hover:bg-indigo-900/50 transition-colors"
337+
disabled={assigningRoles}
338+
className="text-xs flex items-center gap-1.5 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-400 px-3 py-1.5 rounded-full hover:bg-indigo-200 dark:hover:bg-indigo-900/50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
331339
>
332-
<Dices className="w-4 h-4"/>
340+
{assigningRoles ? <Loader2 className="w-4 h-4 animate-spin"/> :
341+
<Dices className="w-4 h-4"/>}
333342
{t('messages.randomAssignRoles')}
334343
</button>
335344
</h3>
336345

346+
{error && (
347+
<div
348+
className="bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg flex items-start gap-3 text-sm animate-in fade-in slide-in-from-top-2">
349+
<AlertCircle className="w-5 h-5 shrink-0 mt-0.5"/>
350+
<div className="flex-1">
351+
<p className="font-medium">{t('errors.error')}</p>
352+
<p className="opacity-90">{error}</p>
353+
</div>
354+
<button
355+
onClick={() => setError(null)}
356+
className="p-1 hover:bg-red-100 dark:hover:bg-red-900/40 rounded transition-colors"
357+
>
358+
<Minus className="w-4 h-4 rotate-45"/>
359+
</button>
360+
</div>
361+
)}
362+
337363
{/* Add Role Control */}
338364
<div className="flex gap-2">
339365
<div className="relative flex-1">

src/dashboard/src/features/game/hooks/useGameActions.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,20 @@ export const useGameActions = (
144144
}));
145145
} catch (error: any) {
146146
console.error("Reset failed", error);
147-
setOverlayState(prev => ({
148-
...prev,
149-
status: 'error',
150-
logs: [...prev.logs, `${t('errors.error')}: ${error.message || t('errors.unknownError')}`],
151-
error: error.message || t('errors.resetFailed')
152-
}));
147+
setOverlayState(prev => {
148+
const errorMsg = `${t('errors.error')}: ${error.message || t('errors.unknownError')}`;
149+
// Dedup log
150+
const logs = [...prev.logs];
151+
if (!logs.some(l => l.includes(error.message))) {
152+
logs.push(errorMsg);
153+
}
154+
return {
155+
...prev,
156+
status: 'error',
157+
logs: logs,
158+
error: error.message || t('errors.resetFailed')
159+
};
160+
});
153161
}
154162
};
155163
performReset();
@@ -180,12 +188,22 @@ export const useGameActions = (
180188
}));
181189
} catch (error: any) {
182190
console.error("Assign failed", error);
183-
setOverlayState(prev => ({
184-
...prev,
185-
status: 'error',
186-
logs: [...prev.logs, `${t('errors.error')}: ${error.message || t('errors.unknownError')}`],
187-
error: error.message || t('errors.assignFailed')
188-
}));
191+
setOverlayState(prev => {
192+
const errorMsg = `${t('errors.error')}: ${error.message || t('errors.unknownError')}`;
193+
// Dedup log: Check if the error message content is already present in any log
194+
const logs = [...prev.logs];
195+
// We check broadly for the error message part to catch both raw backend messages and formatted ones
196+
if (!logs.some(l => l.includes(error.message))) {
197+
logs.push(errorMsg);
198+
}
199+
200+
return {
201+
...prev,
202+
status: 'error',
203+
logs: logs,
204+
error: error.message || t('errors.assignFailed')
205+
};
206+
});
189207
}
190208
};
191209
performRandomAssign();

src/dashboard/src/features/game/hooks/useGameState.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ export const useGameState = (guildId: string | undefined, user: User | null) =>
8686
newState.error = undefined;
8787
newState.title = t('progressOverlay.processing');
8888
} else if (data.message) {
89-
newState.logs = [...prev.logs, data.message];
89+
const trimmedMessage = data.message.trim();
90+
// Check if specific message already exists to avoid any duplicates
91+
if (!prev.logs.some(log => log.trim() === trimmedMessage)) {
92+
newState.logs = [...prev.logs, data.message];
93+
}
9094
}
9195

9296
if (isError) {
@@ -170,7 +174,7 @@ export const useGameState = (guildId: string | undefined, user: User | null) =>
170174
};
171175

172176
loadGameState();
173-
}, [guildId, user, t]);
177+
}, [guildId, user]);
174178

175179
return {
176180
gameState,

src/main/kotlin/dev/robothanzo/werewolf/service/impl/RoleServiceImpl.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,10 @@ class RoleServiceImpl(
293293

294294
gameSessionService.broadcastUpdate(guildId)
295295
} catch (e: Exception) {
296-
log.error("Failed to assign roles: {}", e.message, e)
297-
throw RuntimeException("Failed to assign roles", e)
296+
val errorMessage = e.message ?: "Unknown error"
297+
statusLogger("錯誤: $errorMessage")
298+
log.error("Failed to assign roles: {}", errorMessage, e)
299+
throw RuntimeException(errorMessage, e)
298300
}
299301
}
300302
}

0 commit comments

Comments
 (0)