fix(fe): optimize mobile viewport scaling and ensure persistent auth session
Summary of Changes: Mobile Viewport Optimization & Auth Session Persistence
1. Context & Motivation
- Issue 1 (UI Scaling & Text Wrapping): When viewing on standard Android devices (e.g., OPPO Reno 15 with 360px viewport), UI components appeared oversized compared to larger screens (such as iPhone 17 Pro Max with 440px viewport). Subtitles on the homepage and login page suffered from awkward orphan word line breaks (e.g., single words wrapping onto new lines). Furthermore, in the Profile page, role and status badges were forced onto multiple lines with empty vertical gaps under the avatar.
- Issue 2 (Session Persistence): Users were forced to re-login every time the Mini App was closed and reopened because tokens were overwritten with empty strings during initial app mount, and mobile WebViews do not reliably persist cross-origin cookies.
2. Key Changes
A. Mobile Viewport & Typography Optimization
-
Responsive Root Scaling (
app.scss):- Implemented dynamic base font-size (
15pxon screens<400px,16pxon screens>=400px) combined with-webkit-text-size-adjust: 100%andtext-size-adjust: 100%to universally scale downrem-based spacing and components by ~6.25% on 360px Android devices without affecting larger iOS viewports. - Fine-tuned
.pagepadding to14pxon mobile screens for improved usable horizontal width.
- Implemented dynamic base font-size (
-
Single-Line Subtitle Guarantees (
index.tsx,login.tsx,register.tsx):- Removed
[text-wrap:balance]which was splitting phrase boundaries in half. - Configured
text-[12.5px] min-[390px]:text-sm whitespace-nowrap overflow-hidden text-ellipsison the homepage subtitle ("Quản lý Tài chính Thông minh & Dự báo Dòng tiền"), ensuring it sits on a single line on both 360px and 440px viewports. - Standardized auth subtitles on login and register pages with
text-xs sm:text-sm whitespace-nowrapto eliminate orphan words like "đầu".
- Removed
-
Profile User Card Restructuring (
profile/index.tsx):- Redesigned the user card header into a balanced
items-centerlayout between the avatar (64px) and the user identity block (Name, Email, Badges), eliminating dead space under the avatar. - Tuned badge padding and typography (
text-[10.5px] px-2 py-0.5 whitespace-nowrap), allowing"SUPER_ADMIN"and"Đang hoạt động"to comfortably sit side-by-side on a single row. - Moved the divider and metadata details (User ID, Created At) to span the full width of the card.
- Redesigned the user card header into a balanced
-
Component Sizing Adjustments (
Button.tsx,Card.tsx,Badge.tsx):-
Button: Reduced default styling fromtext-lg px-6 py-2.5to mobile-firsttext-sm sm:text-base px-4 sm:px-5 py-2 sm:py-2.5. -
Card: Updated default padding fromp-6top-4 sm:p-5, reclaiming 16px of horizontal content space. -
Badge: Compacted padding frompx-3 py-1topx-2.5 py-0.5.
-
B. Persistent Authentication & Token Refresh Flow
-
Token Protection in Store (
auth-store.ts):- Updated
setAuthto only updatesafeStoragewhen valid, non-empty tokens are provided, preventing accidental overwriting with empty strings. - Separated
setUserlogic so profile updates do not alter authentication tokens.
- Updated
-
Session Auto-Recovery on App Launch (
layout.tsx):- Replaced the hardcoded empty-string token initialization (
setAuth(response.data, "", "")) with a resilient multi-stage recovery mechanism:- Read stored
accessTokenandrefreshTokenfromsafeStorage. - Attempt
authService.getMe()with the active token. - If
getMe()fails (e.g., 30-minute access token expired), automatically call/auth/refreshusing the 7-dayrefreshTokento obtain new credentials and restore the session transparently. - Only clear auth state when both access and refresh tokens are invalid or expired.
- Read stored
- Replaced the hardcoded empty-string token initialization (
-
API & Interceptor Updates (
auth.service.ts,api-client.ts):- Added
authService.refresh()method. - Removed
/auth/mefrom the blocked auth endpoint list inapiClientresponse interceptor to enable automatic silent refresh on 401s during active usage.
- Added