Skip to content

feat(save): save-first E-01 to E-05 let logged-out learners save and sign in later (dev) - #66

Merged
navidshad merged 2 commits into
devfrom
save-first/extension-dev
Oct 16, 2026
Merged

navidshad merged 2 commits into
devfrom
save-first/extension-dev

Conversation

@navidshad

@navidshad navidshad commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

The same change as #65 (into main), ported to dev. Logged-out learners can save a phrase. It is kept in the extension and sent to their account after they sign in. No server change.

Why: subturtle-doc docs/tech/save-first-implementation.md (rows save-first E-01 to E-05).

save-first E-01 to E-05 (same as #65)

  • E-01: the selection popup button says "Learn more or Save" ("Learn" when saved, also for a phrase saved on this browser). The help text matches.
  • E-02: a logged-out learner gets two buttons on the word card from the first phrase: "Save without login" and "Login to save" (which keeps save-login-prompt_viewed / _clicked; the new button sends save-without-login_clicked). The phrase goes to chrome.storage.local (pendingSaves), one copy per phrase. phrase_saved gets logged_in: false (and true for signed-in saves).
  • E-03: from the 3rd local phrase, a "Sign in to keep your N phrases and review them tomorrow" card with Sign in / Not now. At 50, it replaces Save. Events save-signin-card_viewed / _clicked / _dismissed.
  • E-04: after sign-in, each local phrase goes to the account with createPhrase and deviceId, and leaves the list only when the server accepts it. One run at a time; it stops at the save limit and keeps the rest. Event pending-saves_synced.
  • E-05: the toolbar popup shows "N phrases waiting. Sign in to keep them".

See #65 for the details.

What is different on dev: languages

  • The save window's language row is unchanged. It is still there for signed-in learners.
  • Logged out there is no language state. So a local save also keeps the detected phrase language.
  • During the sync, each phrase gets its language with the save window's own rule (resolveSaveRow):
    • a language the learner has: saved there;
    • a language not added yet, or an unknown one: saved to the active language (like "Save to ").
  • The language goes with the bundle suggestion, the bundle (find and create) and createPhrase. One page saved in two languages gets a bundle per language.
  • Without language profiles (dark launch), nothing is sent, the same as before.
  • If the login has not loaded the language state yet, the sync loads it first.

Decisions different from the work list

How tested

  • The tests from feat(save): save-first E-01 to E-05 let logged-out learners save and sign in later #65, plus three language cases in pending-saves-sync.test.ts (target language per phrase, bundle in that language, one bundle per language for one page).
  • yarn typecheck: clean.
  • yarn test: 49 files, 437 tests pass.
  • yarn build: OK.
  • yarn test:e2e (CI stub settings): 22 of 22 pass.
  • The repo has no lint script.
  • Not checked by hand in Chrome yet.

🤖 Generated with Claude Code

navidshad and others added 2 commits October 16, 2026 21:54
…sign in later (dev port)

Same change as the PR into main (save-first E-01 to E-05), ported to dev:

- save-first E-01: "Learn more or Save" ("Learn" when saved, also for a
  phrase saved on this browser). Help text matches.
- save-first E-02: a logged-out learner gets Save on the word card; the
  phrase goes to chrome.storage.local (pendingSaves). phrase_saved gets
  logged_in (false / true).
- save-first E-03: sign-in card from the 3rd local phrase, required at 50.
- save-first E-04: after sign-in, local phrases go to the account with
  createPhrase and deviceId, one run at a time, stopping at the save limit.
- save-first E-05: the toolbar popup shows "N phrases waiting".

dev only (multilingual round 1): the save window keeps its language row
for signed-in learners. A local save keeps the detected phrase language,
and the sync picks the target language with resolveSaveRow (a language
not added goes to the active language). The language goes with the
bundle suggestion, the bundle and createPhrase; without language profiles
nothing is sent, as before.

Work list: subturtle-doc docs/tech/save-first-implementation.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ave" together

Design change from Navid: from the first phrase on, a logged-out learner
sees both choices on the word card.

- "Save without login" saves on this browser (as before) and sends
  save-without-login_clicked (count).
- "Login to save" opens the login window (source save_prompt). The
  existing save-login-prompt_viewed (once per word, when the choices show)
  and save-login-prompt_clicked events stay on it.
- The soft sign-in card from the 3rd local phrase and the 50-phrase cap
  (only sign-in offered) are unchanged.

Work list: subturtle-doc docs/tech/save-first-implementation.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@navidshad
navidshad merged commit cc3f8d7 into dev Oct 16, 2026
2 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.17.0-dev.9 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant