generated from nhcarrigan/template
feat: debug panel with force unlocks and hard reset (#65)
## Summary - Adds a new **Debug** tab to the game UI with two self-service tools for players with broken save state - **Force Unlocks**: scans the player's save and grants any zones, quests, bosses, and exploration areas they've earned but that are still locked — shows a breakdown of what was unlocked (or reports nothing needed fixing) - **Hard Reset**: wipes progress back to a fresh save (preserving lifetime stats), guarded behind a confirmation modal to prevent accidental clicks ## Files added - `apps/api/src/routes/debug.ts` — two POST endpoints (`/force-unlocks`, `/hard-reset`) - `apps/web/src/components/game/debugPanel.tsx` — the Debug tab UI - `apps/web/src/components/ui/confirmationModal.tsx` — reusable confirmation modal ## Files modified - `apps/api/src/index.ts` — registers the debug router - `packages/types/src/interfaces/api.ts` — adds `ForceUnlocksResponse` type - `packages/types/src/index.ts` — exports the new type - `apps/web/src/api/client.ts` — adds `forceUnlocks()` and `debugHardReset()` API calls - `apps/web/src/context/gameContext.tsx` — wires both functions into game context - `apps/web/src/components/game/gameLayout.tsx` — adds the Debug tab - `apps/web/src/styles.css` — styles for action buttons, cards, result messages, and confirmation modal ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #65 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #65.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file Reusable confirmation modal component for destructive operations.
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import type { JSX } from "react";
|
||||
|
||||
interface ConfirmationModalProperties {
|
||||
readonly title: string;
|
||||
readonly description: string;
|
||||
readonly confirmLabel: string;
|
||||
readonly onConfirm: ()=> void;
|
||||
readonly onCancel: ()=> void;
|
||||
readonly isLoading: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a confirmation modal for destructive operations.
|
||||
* @param props - The modal properties.
|
||||
* @param props.title - The modal heading.
|
||||
* @param props.description - Warning text explaining what the operation does.
|
||||
* @param props.confirmLabel - Label for the confirm button.
|
||||
* @param props.onConfirm - Callback fired when the player confirms.
|
||||
* @param props.onCancel - Callback fired when the player cancels.
|
||||
* @param props.isLoading - Whether the operation is currently in progress.
|
||||
* @returns The JSX element.
|
||||
*/
|
||||
const ConfirmationModal = ({
|
||||
title,
|
||||
description,
|
||||
confirmLabel,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
isLoading,
|
||||
}: ConfirmationModalProperties): JSX.Element => {
|
||||
return (
|
||||
<div className="modal-overlay">
|
||||
<div className="modal">
|
||||
<h2>{title}</h2>
|
||||
<p>{description}</p>
|
||||
<p className="modal-note">{"Are you sure you want to do this?"}</p>
|
||||
<div className="modal-actions">
|
||||
<button
|
||||
className="modal-close-button modal-button-danger"
|
||||
disabled={isLoading}
|
||||
onClick={onConfirm}
|
||||
type="button"
|
||||
>
|
||||
{isLoading
|
||||
? "Working..."
|
||||
: confirmLabel}
|
||||
</button>
|
||||
<button
|
||||
className="modal-close-button"
|
||||
disabled={isLoading}
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{"Cancel"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { ConfirmationModal };
|
||||
Reference in New Issue
Block a user