Commit Graph

37 Commits

Author SHA1 Message Date
bff8cc8624 feature: logger 2026-03-26 17:40:44 +09:00
f1ca5cda75 feat: remove web-push dependency and add event summary links to game table
- Remove web-push and related sub-dependencies (asn1.js, http_ece, etc.) from package.json and bun.lock
- Update AppBar z-index to 8 for proper layering
- Enhance GameTable component:
  - Add Skeleton loading states for event names
  - Introduce EventName component with Link to event detail pages
  - Fix column widths and add row-span logic for event grouping
  - Enable horizontal scrolling for better mobile view
- Add /api/match-summary/:matchId endpoint for frontend event name fetching
- Rename getEventInfo to getMatchSummary in KaiqiuService for consistency
2026-03-26 11:52:25 +09:00
30339596d7 feat(search): support province and city filtering for club search
- Add CascaderProvinceCity component to ClubSearchTable for selecting province/city.
- Update KaiqiuService.findClub to accept and append province/city parameters to the query URL.
- Update server-side API handler to extract province/city from query parameters.
- Improve date parsing logic in event processing to handle invalid start dates gracefully.
- Refactor uidScoreStore to use a loop instead of map for better performance/clarity.
- Add debug logging for profile caching in xcxApi.

The search functionality now supports filtering clubs by administrative division, providing users with more precise search results.
2026-03-25 20:27:51 +09:00
191906192b feat(cache): remove redis caching and add force refresh mechanism
- Remove Redis-based caching logic from uidScoreStore and xcxApi.
- Add force refresh support to uidScoreRequest in GroupingPrediction component.
- Update server API /api/user/nowScores to accept force parameter.
- Always show refresh button in GroupingPrediction regardless of data state.
- Change default sort type in FavPlayersPage to SCORE_DOWN.
- Clean up unused imports from server.ts.

This change ensures user scores are always up-to-date by bypassing cache
when needed, preventing issues with stale data during manual sync operations.
2026-03-25 11:19:59 +09:00
04a347c981 feat(api): add cache and force refresh for club events; fix event watch rate limits
- Introduce Redis caching for event lists to reduce redundant fetches and handle timeouts gracefully. Added a `force` query parameter to bypass cache when needed.
- Added a check in `EventWatchSchedule` to skip processing if player list is empty, preventing errors from rate-limited or failed requests.
- Updated the `listClubEvents` signature to accept the new `force` parameter and modified API endpoints to propagate this flag.
2026-03-24 18:12:39 +09:00
58cf736e82 feat(notification): add click-to-open functionality and cleanup test notification
- Update useFirebaseNotificationProcessor to handle notification clicks by opening the URL from data.url.
- Implement notificationclick event handler in sw.ts to redirect users when a notification is clicked.
- Simplify the registration success notification in index.tsx by removing the unnecessary JSON body argument.
- Ensure seamless navigation when users interact with push notifications by passing the URL through the notification payload.
2026-03-24 17:33:52 +09:00
2774037012 feat(app): add push notification support and event management logic
- Introduce PermissionControlPanel in UserCenter for managing notification permissions.
- Update Service Worker (sw.ts) to handle background push notifications via Firebase Cloud Messaging.
- Implement EventSubscribeService logic to fetch active events, filter expired ones, and clean up subscriptions.
- Refactor KaiqiuService and parsing utilities to include eventId in event details.
- Remove deprecated ScheduleService and inline sendNotification logic.
- Update utility functions to support new types and notification checks.
- Add VAPI public key configuration and update Firebase exports.
2026-03-24 17:21:50 +09:00
94b82ba919 feat: refactor websocket notifications and service caching
Refactor the application to implement native browser push notifications and remove unnecessary Redis caching for performance optimization.

Key changes:
- Introduce a dedicated server topic 'SERVER_PUSH' to handle push notification messages via WebSocket.
- Implement a Service Worker (sw.ts) to capture push events and display system-level notifications, replacing the previous Ant Design toast usage for server messages.
- Add a "Notification Permission" button in the User Center to allow users to request push notification rights.
- Remove Redis caching logic from KaiqiuService (event lists, match details, and member details) to ensure real-time data accuracy, as the cache was causing latency in updates.
- Clean up WebSocket service subscription logic to focus on user-specific events.

This shift from UI-only notifications to system push notifications improves visibility for critical server events (like match updates) even when the user is not on the active tab. Additionally, removing the cache simplifies the codebase and ensures the latest match data is always fetched.
2026-03-23 19:13:39 +09:00
0c82384fd5 feat(api & services): add error handling for club summary and refresh match details
- Add `.catch(() => null)` in `ClubSummary.tsx` to gracefully handle failed API requests and prevent UI crashes.
- Return `null` from `ClubSummary` when the club data is `null` to skip rendering during errors.
- Extract `getMatchInfo` logic into a new static method `getMatchDetail` within `KaiqiuService` for better separation of concerns.
- Update `getClubLocation` and `getEventInfo` to accept an optional `force` parameter, allowing cache bypass when network errors (like '连接超时') occur.
- Remove the old `getMatchInfo` utility function from `server.ts` and update the `/api/match` route to use `KaiqiuService.getMatchDetail`.
2026-03-23 14:33:12 +09:00
76b68c0ea6 refactor(ws): unify WebSocket topic handling and add event subscription
- Refactor `WebSocketService` and `common.ts` to use a unified topic system instead of custom prefixes.
- Replace manual topic string concatenation with `getEventSubKey` and defined `WsServerSendTopics` types.
- Update client-side components (`EventCard`, `GroupingPrediction`) to support real-time event subscriptions and notifications.
- Move `useAuthSocket` and `WebScoketContext` initialization into `AppBarLayout` to ensure WebSocket state is available globally.
- Add error handling to WebSocket message processing in the Bun server.
- Implement a manual "Refresh Current Scores" button for `GroupingPrediction` to fetch fresh `nowScore` data.
- Update `HydrateFallback` UI to display a loading message instead of a refresh button during long load times.
- Add Service Worker (`sw.js`) build route to the Bun server configuration.
2026-03-22 13:00:50 +09:00
fd8257e194 feat(api): add user location management endpoints and database model
- Added `UserLocation` model to `prisma/schema.prisma` to store user location data including coordinates (point geometry), name, avatar, and bindings to Logto and Kaiqiu users.
- Created new API endpoints under `/api/account/location` to handle location operations:
  - `POST`: Create a new location record for a user.
  - `GET`: Retrieve nearby locations based on latitude and longitude.
  - `PUT`: Update an existing location record, including coordinate updates via spatial index.
  - `DELETE`: Remove a specific location record.
- Integrated the custom spatial operations from `xprisma` DAO to support geospatial queries and updates.
- Updated dependencies to include `@mui/icons-material` (and its peer dependencies like `prop-types` and `react-transition-group` which are implicitly required by the new icon components).
- Implemented `verifyLogtoToken` logic to secure the new endpoints and associate locations with authenticated users.

No breaking changes in API contracts; new endpoints are additive.
2026-03-19 00:29:02 +09:00
c70aeda412 feat(auth): add Kaiqiu account binding and update WebSocket architecture
- Add `UserBind` model to Prisma schema for linking Logto and Kaiqiu user IDs.
- Implement `/api/account/bind` endpoint (GET/PUT) to handle Kaiqiu account binding and retrieval.
- Refactor `KaiqiuService` to include a `login` method that performs browser automation-like login on kaiqiuwang.cc using `cheerio` and `fetch`.
- Update `UserCenter` page to include a new `BindKaiqiuAccount` component.
- Restructure `WebSocketService`:
  - Change from a simple global connection map to a per-user client tracking system (`#userClients`).
  - Update topic naming conventions (e.g., `ONLINE_MEMBER_CHANGE` -> `MEMBER_CHANGE`).
  - Add client-side broadcast capabilities for user-specific events like `MY_CLIENT_ONLINE`.
  - Add support for dynamic subscription handling (SUB/UNSUB) via WebSocket messages.
- Update `verifyLogtoToken` to accept either `Headers` or a raw token string for flexibility in WebSocket auth.
- Minor fixes: typo corrections in `WSTopic` enum and commented out debug logs.

BREAKING CHANGE: WebSocket payload structure has changed.
The `ws.data` property now contains a `WsPaylaod` object with a `user` field (previously it was a JSON string of the JWT payload).
The `WSTopic` names have been updated (e.g., `ONLINE_MEMBER_CHANGE` is now `MEMBER_CHANGE`), requiring updates to any client code subscribing to these topics.
2026-03-18 01:18:34 +09:00
09f3ecaca6 feat(WebSocket & Event System): Add real-time updates and event subscription
Introduces WebSocket connectivity for live data updates and a new subscription model for events.

Key changes:
- Integrated WebSocketService to handle open, message, and close events via the /ws endpoint.
- Added EventSubscribeService APIs to manage user subscriptions to specific events (matchId) via REST endpoints (`/api/subscribe-event` and `/api/subscribe-event/:matchId`).
- Implemented custom message protocol (JSON format) for WebSocket communication with defined topics (ONLINE_MEMBER_CHANGE, etc.).
- Updated database schema to include the `EventSubs` model for storing subscriptions.
- Refactored Dockerfile to use `bun prisma db push` for database migrations on startup.
- UI Updates:
  - Replaced the Rate component in FavButton with Star icons for better UX.
  - Adjusted layout of FavButton to be absolute positioned.
  - Added debounce to ClubSummary data fetching.
  - Removed unused `isMobile` import from ClubSummary.
- Utilities: Added helper functions `toCustomMessage` and `fromCustomMessage` for parsing WebSocket messages.
2026-03-17 17:26:52 +09:00
c7faeb1b65 feat(api-versioning): remove git-based versioning and serve via HTML script tag
- 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.
2026-03-17 11:23:25 +09:00
f7cd596084 feat(ui): add app version display and API
- 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.
2026-03-17 10:57:10 +09:00
ce5c523efb fix(index): update event URL format in server configuration
- 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.
2026-03-16 22:45:42 +09:00
86c3b6651b feat(fav-players): optimize un-fav API response and refactor player list UI
- 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.
2026-03-16 19:33:44 +09:00
9c9b3735cb feat: migrate user fav system from session aud to Logto sub
- 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.
2026-03-16 12:45:12 +09:00
93f2cd6525 fix(index): trim club name from event titles and simplify calendar name
- 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.
2026-03-16 02:10:56 +09:00
6bcbff572e fix(i18n): normalize event date parsing for ICS export
- 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.
2026-03-15 09:13:57 +09:00
0f9e80856b refactor(components): optimize event list and search table with pagination persistence
- 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.
2026-03-15 02:33:34 +09:00
4825f41337 fix: conditionally apply geo and location fields in calendar events
- 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.
2026-03-14 20:10:47 +09:00
9657acea64 feat(club): upgrade event calendar subscription and add match status display
- 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.
2026-03-14 19:56:48 +09:00
99fd5778df feat: search club 2026-03-13 20:15:57 +09:00
d323e1d925 feat(game-selector): implement pagination and caching for event list
- 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.
2026-03-13 11:34:23 +09:00
b560684dfb feat(app): split game selector and implement club detail page
- **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.
2026-03-13 10:27:05 +09:00
6f1f8044dd feat(BattleTable): share code 2026-03-11 18:08:39 +09:00
80aebac57a feat: implement user favorite player system with Logto sync
- 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.
2026-03-09 10:16:27 +09:00
7b66b30309 fix(env): move validation to server.ts and add debug logging for missing
variables
2026-03-03 17:46:30 +09:00
e97444244a feat: Add REDIS environment variable and update environment checks
- 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
2026-03-03 14:16:29 +09:00
9e892f6ed1 refactor(api): switch nowScores endpoint from GET query to POST JSON body
- send uids as JSON payload in frontend event loader
- update /api/user/nowScores route to accept POST and parse req.json()
- keep score lookup behavior unchanged
2026-03-03 00:58:58 +09:00
b7d2109f2e refactor(utils): split shared helpers and server scraping modules
- move event scraping/parsing and match lookup logic into src/utils/server.ts
- extract BASE_URL and grouping/round-table helpers into src/utils/common.ts
- update component/service entry imports to new module locations
- remove deprecated src/utils/utils.ts monolith
- clean up unused XCXFindUser type import
- update tests to new utils import path
2026-02-26 00:26:25 +09:00
79c839db00 feat: add current-score grouping flow with cached uid score API
- move shared parsing/grouping helpers into serverUtils and update imports
- add xcxApi singleton in serverUtils
- add Redis-backed uid score store and /api/user/nowScores endpoint
- preload uid scores in event loader and tags in profile loader
- allow grouping prediction to switch sort mode between current/yearly score
- update tags component to consume loader-provided tags
- remove unused zustand game store
- add redis test scaffold and scoreboard component scaffold
2026-02-26 00:13:37 +09:00
6fcd54ed34 fix(Profile): disable uid: 0 2026-02-10 15:15:08 +09:00
bbc6a592f4 feat(global): find user 2026-02-10 11:11:08 +09:00
8831ac456b feat(Profile): GameTable 2026-01-30 11:55:44 +09:00
0fed35fb48 init 2026-01-29 22:00:49 +09:00