- 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.
- Added `dayjs` import for date manipulation in `GamePanel.tsx`.
- Introduced `isPassedGame` memoized value in `GamePanel.tsx` to determine if the game date has passed.
- Updated `GroupingPrediction` component to accept `isPassedGame` prop and adjust `nowScoreGroup` state accordingly.
- Added REDIS environment variable to .env.example
- Updated src/index.tsx to check for multiple required environment variables
- Updated src/utils/server.ts to use REDIS environment variable for RedisClient