╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/ui/Home/Auth/Login.zig│ ╰──────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │228 │ │229 var username_buf: [256]u8 = undefined; │ │230 const username = joinCodepoints(&username_buf, username_input.content.items) orelse {│ │227 - self.status = .unknown_user; │ │231 + self.session.data.login_failure = .unknown_user; │ │232 return; │ │233 }; │ │234 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │235 var password_buf: [256]u8 = undefined; │ │236 const password = joinCodepoints(&password_buf, password_input.content.items) orelse {│ │233 - self.status = .wrong_password; │ │237 + self.session.data.login_failure = .wrong_password; │ │238 return; │ │239 }; │ │240 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │241 const haxy_moment = self.session.haxy_moment orelse { │ │242 // no DB context (e.g. wasm/web rendering path); treat as unknown.│ │239 - self.status = .unknown_user; │ │243 + self.session.data.login_failure = .unknown_user; │ │244 return; │ │245 }; │ │246 const arena = self.session.arena orelse { │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │243 - self.status = .unknown_user; │ │247 + self.session.data.login_failure = .unknown_user;│ │248 return; │ │249 }; │ │250 │ ╰─────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │251 const result = try evt.User.verifyCredentials(DB, repo_opts.hash, haxy_moment, arena, username, password);│ │252 switch (result) { │ │253 .unknown_user => { │ │250 - self.status = .unknown_user; │ │254 + self.session.data.login_failure = .unknown_user; │ │255 return; │ │256 }, │ │257 .wrong_password => { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────╮ │254 - self.status = .wrong_password; │ │258 + self.session.data.login_failure = .wrong_password;│ │259 return; │ │260 }, │ │261 .success => |user_id| { │ ╰───────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │262 // dupe user_id into the arena so the session can hold a stable slice│ │263 const user_id_stable = try arena.allocator().dupe(u8, &user_id); │ │260 - self.session.user_id = user_id_stable; │ │261 - self.status = .success; │ │264 + self.session.data.user_id = user_id_stable; │ │265 + self.session.data.login_failure = null; │ │266 │ │267 // wipe the entered credentials so they don't linger if the │ │268 // user returns to this page after logging out. │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────────╮ │src/ui/Home/Auth/Logout.zig│ ╰───────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │106 } │ │107 │ │108 fn logout(self: *View, root_focus: *Focus) !void { │ │109 - self.session.user_id = null; │ │109 + self.session.data.user_id = null; │ │110 // jump focus back to the users tab — the logout button is about to│ │111 // be hidden by the tab-label swap. │ │112 try root_focus.setFocus(self.users_tab_id); │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Home/AuthTab.zig│ ╰───────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │40 // re-allocating. │ │41 if (self.text_box.box.children.values().len > 0) { │ │42 const text_widget = &self.text_box.box.children.values()[0].widget.text; │ │43 - text_widget.content = if (self.session.user_id != null) "logout" else "login"; │ │43 + text_widget.content = if (self.session.data.user_id != null) "logout" else "login";│ │44 } │ │45 try self.text_box.build(allocator, constraint, root_focus); │ │46 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Home/Header.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │71 } │ │72 │ │73 var self = View{ .box = box, .data = data, .tab_ids = tab_ids }; │ │74 - self.getFocus().child_id = tab_ids[0]; │ │74 + // when a previous login attempt just failed, land on the auth tab so│ │75 + // the user sees the form (with its "(invalid)" label) instead of the│ │76 + // default users list — otherwise the post-redirect page reads as if │ │77 + // the login silently succeeded. │ │78 + self.getFocus().child_id = if (session.data.login_failure != null) │ │79 + tab_ids[auth_tab_index] │ │80 + else │ │81 + tab_ids[0]; │ │82 return self; │ │83 } │ │84 │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯