Skip to content

fix(login): restore ?pick escape hatch and fix 返回一般登入 landing page#233

Merged
YCC3741 merged 2 commits intocodefrom
fix/login-region-duplicate-redirect
Apr 21, 2026
Merged

fix(login): restore ?pick escape hatch and fix 返回一般登入 landing page#233
YCC3741 merged 2 commits intocodefrom
fix/login-region-duplicate-redirect

Conversation

@YCC3741
Copy link
Copy Markdown
Collaborator

@YCC3741 YCC3741 commented Apr 20, 2026

Summary

修兩個會把使用者送到錯誤頁面的 navigation bug。兩個 bug 都是 commit 24a07af?pick=1 escape hatch 時引入的副作用。

Bug 1: 區域選擇頁的 ?pick=1 escape hatch 失效

LoginRegionSelection.vue 同時有兩個 auto-redirect 機制互相打架:

  1. onMounted(舊邏輯):mount 時看 loginRegion 有就馬上 router.replace('/login/id-pass')沒檢查 ?pick沒看 loginMethod(永遠跳 id-pass)。
  2. watch(() => config.loaded, ..., { immediate: true })(commit 24a07af 加的):同樣的 redirect 意圖,但會檢查 ?pick=1、會根據 loginMethod 決定要跳 /login/id-pass 還是 /login/qr

onMounted 比 watcher 早一步同步執行,所以從登入表單按 back 帶 ?pick=1 想回到區域選擇頁時,還沒看到頁面就被 onMounted 踢走 → 設好 region 之後永遠到不了區域選擇頁;QR 模式的 user 還會被 onMounted 默默改回 id-pass。

看起來是 PR #230 cherry-pick 24a07af 時,新的 watcher 加進來但舊的 onMounted 沒清乾淨。

Bug 2: QR / Gamepass 表單的「返回一般登入」按鈕跳到錯地方

QrForm.vue:goBackGamepassForm.vue:goBack 都 push /login?pick=1,把使用者送到區域選擇頁。但 button 上的 i18n key BackRegularLogin →「返回一般登入」/「Back to Regular Login」,「一般登入」明確指 id-pass form,不是區域選擇。

WPF 的對應行為(qr_form.xaml.cs::btn_back_Click)是 App.LoginMethod = Regular + loginMethodChanged(),意思是「在同一個 region 內把模式切回 id-pass」,而不是「重選 region」。

24a07af?pick=1 的時候順手把 QR / Gamepass 的 goBack 也改成用這個機制,但語意上 ?pick=1 是「我要重選 region」,跟「返回一般登入」(=mode switch) 不同。

Changes

Bug 1

  • 砍掉 LoginRegionSelection.vueonMounted block 跟連帶的 onMounted import(watcher 已是 strict superset)
  • 加 5 個 regression test 覆蓋 redirect 決策的所有分支:
    • 存 TW + 預設 loginMethod → 跳 /login/id-pass
    • 存 TW + loginMethod=1 → 跳 /login/qr
    • 存 HK + loginMethod=1 → 仍跳 /login/id-pass(HK 無 QR)
    • 有 saved region + ?pick=1 → 留在 picker
    • 無 saved region → 留在 picker

Bug 2

  • QrForm.vue:goBack + GamepassForm.vue:goBack 改成 router.push('/login/id-pass')
  • QrForm.vue 的 docblock 對應更新(原 docblock 自己描述 WPF 行為跟 SPA implementation 已經對不上)
  • GamepassForm.vue:goBack 加 inline comment 說明為什麼不用 ?pick=1
  • 保留 onMounted 內 region != TW 的 fallback 仍然是 ?pick=1(那是 region 校驗失敗,本來就該回 picker)
  • 兩個 spec 加 /login/id-pass route stub、改 expect、補 regression 註解

Test plan

  • npx vitest run tests/unit/pages/{LoginRegionSelection,QrForm,GamepassForm}.spec.ts — 37 / 37 pass
  • npx vue-tsc --noEmit — clean
  • Lint — clean
  • 手測:設好 region 進入 id-pass → 按 back → 應該看到區域選擇頁
  • 手測:設 QR 模式 → 重啟 → 應該直接進 QR 而不是 id-pass
  • 手測:QR 表單點「返回一般登入」→ 應該到 id-pass form(同 region),不是區域選擇頁
  • 手測:Gamepass 表單點「返回一般登入」→ 應該到 id-pass form(同 region),不是區域選擇頁

YCC3741 added 2 commits April 21, 2026 07:53
…ck escape hatch

LoginRegionSelection.vue had two competing auto-redirect mechanisms:

1. `onMounted` (legacy): if `loginRegion` was saved, immediately
   `router.replace('/login/id-pass')`. Did NOT check `route.query.pick`,
   did NOT consult `loginMethod` (always landed on id-pass).
2. `watch(() => config.loaded, ..., { immediate: true })` added by
   commit 24a07af: same redirect intent, but correctly honours the
   `?pick=1` escape hatch and routes to `/login/qr` when
   `loginMethod === '1'` on TW.

Because `onMounted` ran synchronously before the watcher's config-loaded
trigger, every back-button navigation from a login form (which appends
`?pick=1` per 24a07af's design) got bounced straight back to id-pass —
the picker became unreachable after first launch, and QR-mode users
were silently downgraded to id-pass on every return trip.

This looks like a leftover from cherry-picking 24a07af in PR #230: the
new watcher was added but the old `onMounted` was never removed.

Drop the `onMounted` block (and its now-unused import). The watcher
with `immediate: true` already covers first-mount, and its logic is
strictly a superset of the deleted block.

Add regression tests covering all five branches of the redirect
decision so the duplication can't silently come back:
- saved TW + default loginMethod → /login/id-pass
- saved TW + loginMethod=1       → /login/qr
- saved HK + loginMethod=1       → /login/id-pass (HK has no QR)
- saved region + ?pick=1         → stays on picker
- no saved region                → stays on picker
QrForm.vue:goBack and GamepassForm.vue:goBack both pushed
`/login?pick=1`, which sent the user back to the region picker. The
button label is "返回一般登入" / "Back to Regular Login" — "regular
login" means the id-pass form within the same region, not the region
picker.

This was the SPA side of the bug paired with the duplicate
`onMounted` redirect fix earlier in this PR: 24a07af added the
`?pick=1` escape hatch for legitimate "re-pick region" flows, but
the QR / Gamepass back buttons were retrofitted to use the same
mechanism even though their semantics are different (mode switch
within a region, not region re-pick).

WPF parity: `qr_form.xaml.cs::btn_back_Click` flips
`App.LoginMethod = Regular` and re-runs `loginMethodChanged()`, which
lands on the regular id-pass form — never the region picker.

Both forms now `router.push('/login/id-pass')` directly. The
`onMounted` HK pre-flight guards (QrForm:241, GamepassForm:274) keep
their `?pick=1` redirect — that path *is* a region rejection and
correctly belongs at the picker.

Update the two affected specs to:
- register a `/login/id-pass` route stub in the harness routers
- assert the back-button target is `/login/id-pass`
- document the regression in the test name + body
@YCC3741 YCC3741 changed the title fix(login-region): remove duplicate onMounted redirect that broke ?pick escape hatch fix(login): restore ?pick escape hatch and fix 返回一般登入 landing page Apr 21, 2026
@YCC3741 YCC3741 self-assigned this Apr 21, 2026
@YCC3741 YCC3741 merged commit 3dfae70 into code Apr 21, 2026
2 checks passed
@YCC3741 YCC3741 deleted the fix/login-region-duplicate-redirect branch April 21, 2026 00:25
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.

1 participant