- Remove `getGitHash` function from `src/utils/server.ts` as it relied on `.git` directory presence which is not available in production builds.
- Remove the `/api/app-version` endpoint from `src/index.tsx` since fetching version via API is no longer needed.
- Update `src/hooks/useAppVersion.ts` to derive the version directly from the `src` attribute of a script tag in the HTML head.
- This change improves performance by avoiding an extra API request and ensures version accuracy across all deployment environments without requiring Git metadata.
- Removed unused imports from Ant Design (`message as AntdMessage`, `StarFilled`, `ShopTwoTone`, `DeleteOutlined`, `UploadOutlined`) and `@ant-design/icons`.
- Removed unused `type IdTokenClaims` import from `@logto/react`.
- Updated the logic in the empty list state: the "Log in to view cloud collection" button now only displays when the user is NOT authenticated (`!isAuthenticated`). Previously, it showed even when logged in, which was misleading.
This cleans up the codebase and improves the user experience on the Favorite Players page.
- Add `getGitHash` utility to extract the git commit hash from the `.git/HEAD` file.
- Expose a new `/api/app-version` endpoint on the server to return the current version.
- Implement a `useAppVersion` hook to fetch the version asynchronously.
- Display the app version (e.g., `app version: a1b2c3d`) in the User Center UI for both authenticated and unauthenticated users.
- This helps in tracking which version of the application is currently running in production.
The AppBar container was previously positioned exactly at the bottom of the viewport, causing a potential 1px gap or overflow issue on certain screens.
- Changed `bottom` from `0` to `-1px` to pull the bar slightly up.
- Adjusted `left` to `-2px` and `width` to `calc(100vw + 4px)` to compensate for the negative left offset and ensure the bar spans the full visible area without horizontal scroll.
This ensures the fixed bar aligns perfectly with the viewport edges in all scenarios.
- Move `initResultMap` and `buildMatchGroupTable` outside the component to reduce closure dependencies.
- Update `ClubEventList` to remove obsolete page key storage logic.
- Add `MATCH_RESULT_MAP_KEY` constant to `utils/constants.ts`.
- Refactor `useMemo` and `useCallback` hooks to rely on the extracted functions.
- Ensure consistent dependency arrays in callbacks for reliable re-renders.
- Changed the `url` property in the serve configuration from a commented-out placeholder to an active template string.
- The new URL format `https://tt.ksr.la/event/${e.matchId}` replaces the previous implementation where the URL was disabled.
- This ensures that event links are correctly generated and clickable within the calendar view, improving user navigation to event details.
- Modify the DELETE /api/fav endpoint to include the player uid in the response JSON.
- Refactor FavPlayersPage to remove explicit dependency on `aud` for API calls, relying solely on `useAuthHeaders`.
- Add a dedicated "un-fav" button to player cards to allow users to unfollow individual players.
- Implement logic to distinguish between local un-fav (for unauthenticated users) and server-side un-fav (for authenticated users).
- Improve UI layout using `styled-components` and updated Ant Design components (`Typography.Title`).
- Add a link to sign in and view cloud favorites when the local list is empty.
- Add 'admin' scope to Logto configuration in frontend.tsx.
- Externalize Logto appId to common.ts utils for better configuration management.
- Remove `isAuthExpired` check in UserCenter.tsx and always show the "Re-login" button.
- Moved header logic (background, avatar, title, notice button) from ClubEventsPage into a new ClubSummary component.
- Updated ClubEventsPage to use ClubSummary instead of managing layout and state directly.
- Fixed `onClick` handler in ClubSummary to correctly spread the `info.geo` object when passing to `openWebMapRaw`.
- Removed unused imports and state from ClubEventsPage.
- Centralized Logto domain and API base URLs in `common.ts` to avoid duplication.
- Replaced deprecated `Modal.useModal` with `App.useApp().modal` for consistent Ant Design usage.
- Refactored `useAutoLogin` hook to handle token expiration checks and trigger re-authentication.
- Updated `UserCenter` and `FavPlayersPage` to use the new `autoSignIn` flow.
- Removed the `useAuthHeaders` hook as logic was consolidated into `useAutoLogin`.
- Added `AUTH_CALLBACK_URL` and `USER_CENTER_URL` constants for cleaner routing.
- In `useAuthHeaders`, import `useAutoLogin` and trigger login if `getAccessToken` returns a falsy value. This handles edge cases where the token is expired or missing during an API call.
- In `useAutoLogin`, set the default redirect URL to `window.location.pathname` to ensure users return to the page they were on before logging in.
- Update database schema to rename `UserFav` to `LogtoUserFav` with clearer field names (`logto_uid`, `kaiqiu_uid`).
- Bump `jose` dependency to v6.2.1 for improved JWT verification.
- Configure `@logto/react` to request the correct resource token for API access.
- Implement token verification on the server side using `jose` and `jwtVerify`.
- Update API routes (`/api/fav`) to extract the user ID from the verified JWT `sub` claim instead of the URL `aud` parameter.
- Refactor frontend components (`FavButton`, `FavePlayersPage`) to use `useAuthHeaders` for fetching auth headers instead of manual token claims extraction.
- Clean up unused migration and DAO functions related to the old `aud`-based logic.
Added link to ./logo.jpg as an apple-touch-icon in index.html to
ensure proper icon display when users add the site to their home
screen on iOS devices.
- Added `isRunningStandalone` utility in `src/utils/front.ts` to detect if the app is running as a standalone PWA or in a native container (iOS Safari, Android Chrome, etc.).
- Updated `AppBar.tsx` to conditionally apply bottom padding only when running in standalone mode, ensuring better layout alignment within custom containers.
- Modified `title` generation to remove the club name prefix if it exists.
- Updated `calName` to display only the club name instead of adding "的比赛" suffix.
- This prevents redundant information in the calendar event titles.
- Update `openMapDirection` to `openWebMapRaw` in `utils/front.ts` to open
maps in a new browser tab (`_blank`) using raw WGS-84 coordinates.
- Adjust URL schemes for Google, AMap, Baidu, Tencent, and Apple Maps to
support direct web navigation with `coordinate` parameters.
- Update `ClubSummary.tsx` to use `openWebMapRaw` and change the map button
label from "Navigation" to "View Location" with a new icon.
- Add `padding-bottom` to `AppBar.tsx` in `AppBarLayout.tsx` to accommodate
the increased bottom padding required by the updated AppBar styling.
- Remove the "Home" FloatButton from `ProfilePage.tsx` and update `routes.tsx`
to remove the unused `ActionButtonLayout` import.
- Update navigation handlers in `AppBar.tsx` to use `replace: true` for smoother
state management without creating new browser history entries.
- Added a "Navigation" button in ClubSummary that opens a Dropdown menu.
- Supported multiple map types: Google, Apple, AMap, Tencent, and Baidu.
- Mobile-only features (AMap, Tencent, Baidu) are disabled on desktop devices.
- Added `geo` property to `ClubDetail` type to support location data.
- Implemented `openMapDirection` utility to launch specific map apps based on the selected type.
- Conditionally render the "View Announcement" button only if an article exists.
- Updated BaseLayout export name from `Layout` to `BaseLayout` for consistency.
- Update `src/index.tsx` to use a unified `ics.convertTimestampToArray` helper
instead of manually parsing formatted strings. This ensures consistent timestamp
handling across different environments.
- Remove the custom `HydrateFallback` and `Layout` components from `src/routes.tsx`.
- Import the existing `HydrateFallback` and `Layout` implementations from their
respective component files (`./components/HydrateFallback` and `./components/Layout/BaseLayout`) to reduce code duplication and improve maintainability.
- Deleted the custom `useRunOnce` hook as its functionality is no longer needed.
- Refactored `EventCard` to determine `type` (countup/countdown) dynamically based on the event state and current time.
- Updated `EventCard` to pass `type` and `format` separately to the `Statistic.Timer` component, removing the need for string formatting logic inside the component.
- Modified `ClubEventList` to add a 300ms delay on page initialization, ensuring the component is fully mounted before triggering the initial fetch logic.
- Refactor ClubEventList to support persistent page state in sessionStorage and dynamic toggle for finished events.
- Move pagination logic to useRunOnce hook for initialization, ensuring correct state restoration.
- Update ClubSearchTable to support "My Favorites" tab, using useRef to cache search results for different club types.
- Enhance EventCard with precise time formatting (HH:mm:ss) and dynamic countdown logic using dayjs timezone.
- Persist club selection in GameSelector using local storage and integrate ClubSummary component.
- Fix geo data handling in KaiqiuService, ensuring coordinates are correctly passed to iCalendar generator.
- Remove unused imports and simplify component structure across affected files.
- Only include 'geo' object in the event attributes if valid latitude/longitude exists.
- Conditionally add 'location' field only when it is present on the event.
- Removed the 'noGeo' flag logic for conditional spreading, simplifying the map operation.
- Ensures clean event data without empty geo/location properties in the generated calendar file.
- Refactor ClubEventList to subscribe to all club events instead of just the current page, removing pagination from the ICS URL.
- Enhance ICS generation for club subscriptions:
- Fetch all non-finished events across pages.
- Include geographic location (lat/lon) in the event metadata.
- Add 2-hour alarms (display and audio) to all subscribed events.
- Improve EventCard status display with logic for 'Finished', 'In Progress', and countdown formats.
- Update KaiqiuService to parse match status (isProcessing, isFinished) and location name accurately.
- Integrate dayjs timezone (Asia/Tokyo) and UTC plugins across index.tsx, services, and types.
- Update IEventInfo interface to include isProcessing and location fields.
- Add 'Club' vs 'Points Club' filter in `ClubSearchTable` using Radio buttons.
- Update `searchClub` request to accept and pass `clubType` parameter to the backend API.
- Refactor logic in `ClubEventList` to determine "Show All" button visibility based on whether all items are finished or not finished, rather than just a fixed count.
- Add custom CSS (styled-components) to limit the height of the game selector drawer for better UX.
- Update backend service `KaiqiuService` to handle the new query parameters for filtering clubs by type.
- Add 'ics' dependency to package.json and update lockfile.
- Introduce pagination support in `ClubEventList` component (Ant Design Pagination + Spin loading state).
- Refactor `GameSelector` to fetch paginated data (`page` query parameter) and manage page state.
- Update `KaiqiuService` to:
- Add Redis caching for event lists (1 hour TTL) and individual match details (10 hours TTL).
- Implement `listClubEvents` method with pagination support (fetching HTML, parsing titles/urls/status, extracting total count).
- Update `getEventInfo` to utilize cached data.
- Update server routes (`index.tsx`, `routes.tsx`) to handle query parameters and pass paginated responses to the frontend.
- Fix logic in `GroupingPrediction` to set group length when players <= 12.
This change improves performance by reducing initial load times through pagination and caching, preventing UI freezing with large event lists.
- **Frontend Refactoring**: Extracted EventCard logic and finished game filtering from GameSelector into a new ClubEventsList component. Removed direct routing logic (handleGameClick, navigate) from App.tsx in favor of router loaders.
- **New Feature - Club Detail Page**: Implemented /club/:id route with ClubEventsPage. Added server-side loader to fetch club info and events in parallel via new API endpoints (/api/club/find, /api/club/:id). Created KaiqiuService for direct data fetching.
- **API & Types**: Extended IEventInfo with isFinished flag; updated server-side parsing in utils/server.ts. Added ClubInfo type definition. Migrated club search and filtering logic to the server side.
- **Dependencies**: Updated antd from 6.2.1 to 6.3.2.
- Add `isFav` selector to `useFavPlayerStore` to determine initial button state immediately.
- Initialize `FavButton` value based on the store's `isFav` result instead of a stale local state.
- In `FavePlayersPage`, integrate Ant Design message hooks for user feedback during server sync.
- Show "syncing" loading indicator when starting the sync process.
- Show "synced" success notification upon completion.
- Enhance the "Clear Local Favorites" confirmation dialog:
- Update warning text to indicate the action is irreversible.
- Add custom button labels ("清空", "取消").
- Make the confirm button dangerous and add a delete icon for better UX.
- Updated the styling and structure of the BattleTable component for better layout and readability.
- Added expandable functionality to the GroupMember component's drawer.
- Adjusted styles and content in BattleTable to improve the visual presentation and functionality.
- Add "Clear Current Round" and "Clear All Groups" buttons to reset specific or entire match results.
- Implement a summary Table showing current scores, predicted scores after the latest round, and score differentials.
- Import necessary Ant Design components (Button, Table) and icons (ClearOutlined).
- Refactor `buildMatchGroupTable` to return full arrays instead of filtering out falsy values.
- Disable row hover effect in GroupMember table for cleaner appearance.
- Initialize `resultMap` from `localStorage` on component mount if data exists.
- Save updated `resultMap` back to `localStorage` when the component unmounts.
- Removed debug console.log statement for cleaner logs.
- Move `BattleTable` logic from `GroupMember` to its own `BattleTable.tsx` component.
- Clean up `GroupMember` by removing unused imports (`Divider`, `Flex`, `Space`, `Table`, `getRoundTable`).
- Add new utility functions in `src/utils/common.ts`:
- `higherWin` and `lowerWin` to calculate scores based on point difference thresholds.
- `calculate` to determine the final score return value based on win/loss status.
- Refactor `useHandleSignInCallback` to return only hook data without an internal callback.
- Move redirect logic into a separate `useEffect` to decouple navigation from the callback lifecycle.
- Ensure the user is redirected to the saved path or `/user-center` immediately upon authentication.
- Migrate from static `Modal.confirm` to `App.useModal` in UserCenter for better context support.
- Refactor Logto Callback page:
- Remove unused `useEffect` dependency on `isAuthenticated`.
- Inline redirect logic directly into the `onSuccess` callback of `useHandleSignInCallback`.
- Preserve existing redirect flow logic while simplifying the component structure.
- Cache user profile data in Redis with 10-minute expiration in XcxAPI service to reduce API overhead.
- Added a refresh/sync button on FavPlayersPage to manually trigger fetching players from the account.
- Refactored authentication logic to properly set and use ID token claims for syncing.
- Improved UX by removing automatic view switching logic that caused layout shifts, relying on state-driven rendering instead.
- Unified login redirect flow using the new `useAutoLogin` hook.
Update the label for the LOCAL filter option to reference `localList.length` instead of `list.length`, ensuring the item count displayed in the dropdown matches the actual filtered list size.
File: src/page/FavPlayersPage.tsx
- { label: `${ShowType.LOCAL}(${list.length})`, ... }
+ { label: `${ShowType.LOCAL}(${localList.length})`, ... }
- Add Prisma code generation in Dockerfile build step.
- Implement instant state updates for favoriting players via store hooks.
- Enhance 'FavPlayersPage' with:
- New "Sync to cloud" and "Clear local favorites" actions.
- Updated tabs showing counts for local vs. account favorites.
- Auto-detection of view mode based on authentication status.
- Add auto-login support in 'UserCenter' triggered by query parameter `autoSignIn=true`.
- Add `FavPlayerDAO` for database operations (create, read, delete, check) against `user_fav` table.
- Integrate Prisma ORM with MariaDB adapter in `src/prisma/db.ts`.
- Implement backend API routes (`/api/fav`) to handle GET, PUT, and DELETE requests for managing favorites based on user audience (aud).
- Create `FavePlayersPage` with support for:
- Viewing local stored favorites.
- Syncing server-side favorites via Logto authentication.
- Visual distinction between "Local" and "Account" favorite lists using Segmented control.
- Loading states and empty state handling with Ant Design components.
- Enhance `Logto/Callback` to redirect users back to their intended destination (e.g., `FavePlayersPage`) after authentication if a `redirect` param was stored in session storage.
- Update `UserCenter` page to include "Backup Codes" management option under account settings.
- Add necessary dependencies: `@logto/react`, `ahooks`, and update UI imports accordingly.
- Add @logto/react dependencies to package.json and lockfile.
- Replace custom App layout with LogtoProvider for authentication handling.
- Configure Logto settings (endpoint, appId) in frontend.tsx.
- Refactor FindUserPage search logic to trigger request on value change instead of manual search key refresh.
- Corrected the default value assignment for REDIS_CACHE_HOUR using logical OR instead of nullish coalescing.
- Added a debug log to output the cache hour value.
- Added error handling for redis.get calls to ensure they return a string or an empty string in case of failure.
- Added REDIS_CACHE_HOUR to .env.example and src/utils/server.ts.
- Updated TIMEOUT usage in src/services/uidScoreStore.ts and src/utils/server.ts to use REDIS_CACHE_HOUR.
- Increased the cache expiration time for event lists from 30 minutes to 72 hours.
- Increased the cache expiration time for match info from 3 minutes to 72 hours.