Skip to content

fix(client): fix progress download, upload, and completion persistence (#538) - #581

Open
myersdennis94 wants to merge 1 commit into
leanprover-community:mainfrom
myersdennis94:fix/issue-538-download-progress
Open

myersdennis94 wants to merge 1 commit into
leanprover-community:mainfrom
myersdennis94:fix/issue-538-download-progress

Conversation

@myersdennis94

Copy link
Copy Markdown

…e (#538)Fixes #538

What was wrong

  1. Download Progress (#538):
    • downloadProgress interpolated gameId (e.g. g/owner/repo) and new Date().toLocaleDateString() directly into a.download, introducing / path separators into the downloaded filename, and did not guard against missing gameId/gameProgress.
    • UploadPopup duplicated the raw downloadFile call with the same unsanitized filename instead of reusing downloadProgress.
  2. Upload Progress:
    • In UploadPopup, setPopup(null) was called synchronously right after fileReader.readAsText(file)—outside fileReader.onload—unmounting UploadPopup before onload could call setProgress.
    • JSON.parse had no error handling or validation for partial/wrapped game_progress JSON structures, and clicking the upload button lacked ev.preventDefault().
  3. Progress Persistence & Display (since #465 and #492):
    • When DualEditorMain was removed in #492, the useEffect that persisted completed: true (completedAtom) and unlocked newly proved items (inventoryAtom) on proof?.completed was dropped, so solving levels never marked them completed or populated inventory in localStorage.
    • currentInventoryTilesAtom read from an unused userInventoryAtom instead of inventoryAtom and filtered out locked tiles before unlocking items present in the user's inventory.
    • In world-tree-atoms.ts, levelsCompletedAtomFamily had a stray space in ${worldId}: ${i} and only checked 0 .. worldSize - 1 (skipping the last level of each world), and worldDependenciesCompletedAtomFamily checked worldCompletedAtom(worldId) instead of the prerequisite source world it[0].

What this changes

  • Guards downloadProgress and downloadFile, sanitizes the download filename (lean4game-<owner_repo>-YYYY-MM-DD.json), revokes the object URL after download, and reuses downloadProgress in UploadPopup.
  • Moves setPopup(null) inside fileReader.onload in UploadPopup, validates and normalizes uploaded JSON (supporting both single-game GameProgress and { games: { [gameId]: ... } }), and adds ev.preventDefault().
  • Restores the proof?.completed effect in PlayableLevel.tsx (guarded by !levelInfoIsLoading && levelInfo?.index === levelId to avoid premature completion during level transitions as noted in #494) and clears codeAtom on erase in ErasePopup.
  • Fixes currentInventoryTilesAtom in inventory-atoms.ts and world/level completion lookups in world-tree-atoms.ts.
  • Fills in the Erase, Download, and Upload specs in cypress/e2e/01-basic-interface.cy.ts.

How it was tested

  • npx cypress run --spec cypress/e2e/01-basic-interface.cy.ts: 10/10 passing (including downloading lean4game-test_TestGame-YYYY-MM-DD.json and verifying its contents, and uploading a progress JSON file and verifying localStorage persistence).
  • npx i18next-scanner --config i18next-scanner.config.cjs in client/: no parse errors on modified components.
  • npm run build:client succeeds with zero TypeScript errors.

@myersdennis94

Copy link
Copy Markdown
Author

I just found Lean Game Server recently, thanks for hosting this! I ran into this issue and wanted to help but I'm limited on React experience and don't know the codebase any. As such, I used Gemini in Antigravity to help diagnose and fix, attempting to conform to style and paradigms present within the project.

I tried my best to understand all changes but please give everything a thorough lookover.

For the curious, I used a mixture of Gemini 3.8 Flash and Gemini 4 Argon inside the Antigravity IDE.

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Download yields empty .json

1 participant