Commit Graph

114 Commits

Author SHA1 Message Date
admin e7a9e7abe5 feat(chat): unlock paid messages before payment 2026-06-30 18:56:17 +08:00
admin 9cff16e2d9 refactor(chat): tighten media cache boundaries 2026-06-30 16:12:02 +08:00
admin ccd2d6bd48 feat(media): implement caching for chat media and update components to use cached media 2026-06-30 15:59:33 +08:00
admin 958a0f8ffd feat(chat): handle credit-gated send responses 2026-06-30 14:17:14 +08:00
admin cee63e8658 fix(chat): use weekly limit for message quota 2026-06-29 18:40:44 +08:00
admin 0bae53bfba feat: implement lazy singleton pattern for repository instances and update related imports 2026-06-29 17:25:41 +08:00
admin 80d6563ffb refactor(chat): remove unused upgrade state fields 2026-06-29 16:32:11 +08:00
admin 61796c732f feat(chat): restore image viewer after payment 2026-06-29 16:19:48 +08:00
admin 6273cd1bbe test(chat-machine): add test for ignoring repeated user login during active session 2026-06-29 15:49:03 +08:00
admin 934b92502b fix(chat): clear limit prompt after payment 2026-06-29 11:27:39 +08:00
admin b7779878cf feat(chat): unlock history after payment 2026-06-29 10:53:52 +08:00
admin 1b73c3ac10 refactor(chat): remove private unlock machine flow 2026-06-26 19:17:29 +08:00
admin e9fc001a6f refactor(chat): remove vip websocket session flow 2026-06-26 18:35:26 +08:00
admin 58236453ed fix(chat): track replies by queued batch 2026-06-26 11:42:17 +08:00
admin fe85af0cd7 fix(chat): queue outgoing messages 2026-06-26 11:11:43 +08:00
admin 6081f2896a test(stores): add state machine coverage 2026-06-25 13:28:08 +08:00
admin 0bff65dd32 feat(docs): add simplified API documentation for chat messages 2026-06-25 12:06:49 +08:00
admin 8d956bc95d fix(chat): render locked voice messages correctly 2026-06-25 12:04:38 +08:00
admin cd836cda43 feat(chat): add voice message bubbles 2026-06-25 11:13:25 +08:00
admin c288148c12 fix(chat): remove dynamic upgradeHint for daily limit message 2026-06-24 18:18:21 +08:00
admin 42c03f8901 feat(chat): migrate chat protocol to lock detail 2026-06-24 14:06:30 +08:00
admin 3e766a0ecd fix(chat): preserve private send response fields 2026-06-24 11:02:15 +08:00
admin f80b5215a9 feat(chat): log websocket traffic 2026-06-24 10:48:36 +08:00
admin a571867620 fix(chat): hide text for ai image messages 2026-06-24 10:19:30 +08:00
admin bfbf7ee91a feat(app): improve payment and paywall UX 2026-06-24 10:02:22 +08:00
admin f14b8a48d2 fix(chat): handle guest total limit 2026-06-23 15:14:17 +08:00
admin 7dd4878d7d fix(chat): constrain auth state transitions 2026-06-23 14:10:59 +08:00
admin ebd44c4980 feat(chat): add private message unlock flow 2026-06-23 13:21:57 +08:00
admin 6bcc070ba1 refactor(chat): rely on server message limits 2026-06-23 11:20:48 +08:00
admin d81abd6efd feat(chat): support ai photo viewing 2026-06-23 10:34:02 +08:00
admin 27021f9328 fix(chat): normalize message date headers 2026-06-22 18:23:50 +08:00
admin 6ff1accad5 refactor(chat): split sessions by vip status 2026-06-22 15:11:57 +08:00
admin 61fd4ca916 feat(chat): handle daily message paywall 2026-06-22 10:46:17 +08:00
admin d87bfcc859 refactor(chat): remove commented-out code in guestSession 2026-06-18 15:47:24 +08:00
admin 812a3e41b9 refactor(logging): centralize console output 2026-06-18 13:34:19 +08:00
admin f600e11d55 refactor(auth): centralize login status sync 2026-06-18 12:52:49 +08:00
admin 0d0dabaace refactor(utils): add barrel exports 2026-06-18 11:58:50 +08:00
admin 5d66cef85c refactor(dto): move app models into dto layer 2026-06-17 17:34:55 +08:00
admin 0a9abc2502 fix(auth): stop parsing logout response body (avoids ZodError on null data)
Root cause: backend `/auth/logout` returns `{ success: true, data: null }`
(no business payload for a fire-and-forget endpoint). The previous
`AuthApi.logout` ran `unwrap(env)` (which passes null through, since
null is defined) and then `LogoutResponse.fromJson(null)`, which
Zod-parses as `z.object(...)` and throws "Invalid input: expected
object, received null".

The error was caught in `AuthRepository.logout` with
`console.warn(... clearing local anyway)` — logout actually still
worked (local clear ran), but a noisy red ZodError hit the console on
every logout click.

Fix: align `AuthApi.logout` with the existing fire-and-forget pattern
used by `register` and `sendCode` — call `httpClient` and ignore the
response body. Drop the now-unused `LogoutResponse` import.

`AuthRepository.logout` already discards the return value, so the
`Promise<LogoutResponse> → Promise<void>` signature change is safe.

Bundled in this commit (unrelated):
- chat-machine.actors.ts / user-machine.ts: removed stale design-doc
  comment blocks (IDE/linter cleanup)
- user-machine.actors.ts: removed redundant `userStorage.clearUserData()`
  from `userLogoutActor` — `authRepo.logout` already clears local
  user data, so this was a no-op duplicate.
- sidebar-screen.tsx: removed one stale comment line.
2026-06-16 18:34:55 +08:00
admin 8b6e38d3cb feat(chat): prepend greeting message when chat history is empty
On first chat open (or when both local and network return empty),
the chat screen would render completely blank, which feels cold and
broken. Prepend a single AI persona greeting as the first message so
the first impression is warm.

Trigger:
- Final returned messages array is empty
- Either network succeeds with empty result, or network fails and local
  is also empty

Design notes:
- Greeting is NOT persisted to local/network — pure UI-layer fallback.
  Once the user sends a real message, network has content and the
  greeting no longer appears.
- If the user closes the app without ever sending a message and reopens,
  the greeting reappears (intentional: "warm first frame on each cold
  start").
- Rendered as an AI bubble (isFromAI: true) so the visual style matches
  the AI persona.
2026-06-16 17:56:03 +08:00
admin 2792d0c9c5 feat(chat): implement WebSocket message sending and integrate with chat state machine 2026-06-16 16:50:57 +08:00
admin dcb6312fa3 feat(chat): add quota-exhausted banner for guest users
Introduce ChatQuotaExhaustedBanner component that displays a pink gradient
banner with an "Unlock your membership to continue" CTA when a guest user's
free chat quota has been exhausted. The banner is shown in ChatScreen when
isGuest is true, quota has loaded, and the chat state machine's
quotaExceededTrigger has been incremented by a quota guard. Default click
navigates to /subscription, with an optional onUnlock callback for
overrides/tests. Styles align with the existing splash and sidebar VIP
card visual language.
2026-06-16 15:18:11 +08:00
admin 9ffa30cc03 style: remove markdown bold syntax from code comments
Remove `**...**` emphasis markers from inline comments and JSDoc blocks across
auth and chat components, machine mappers, and quota helpers. These are
plain code comments, not rendered markdown, so the bold syntax was noise.

Files touched:
- src/app/auth/components/auth-screen.tsx
- src/app/chat/components/chat-header.tsx
- src/app/chat/components/chat-screen.tsx
- chat machine mapper / quota helpers

No functional or behavioral changes.
2026-06-16 14:06:31 +08:00
admin cba52884a3 chore: clean up migration comments and unused params
Remove obsolete Dart migration notes and route handling comments from splash-button.tsx and auth-machine.ts, and drop the unused `self` parameter from `chatWebSocketActor` callback signature.
2026-06-16 12:01:42 +08:00
admin e44cc7e2f3 feat(sidebar): redesign sidebar UI with three user states (light theme)
Replace the dark sidebar theme with a light-themed three-state UI
matching the design references:

- guest  : pink "login" pill in user row, no status pill on VIP card,
           "Activate VIP Membership" button shown
- member : "VIP membership not activated" subtitle, no status pill,
           "Activate VIP Membership" button shown
- vip    : pink "VIP Member" pill with diamond icon, "Activated" pill
           in VIP card header, no Activate button

Decompose into BackBar, UserHeader, VipBenefitsCard, and VoicePackageCard
under src/app/sidebar/components/. Delete obsolete GuestPanel,
UserInfoCard, and VipCta.

Lift VIP_BENEFITS to a shared src/data/constants/vip-benefits.ts so the
sidebar and subscription page render identical benefit copy.

Add five sidebar tokens (--color-card-surface, --color-voice-gradient-*
--border-card, --shadow-card, --color-pill-bg) to src/tokens/colors.css.

Includes barrelsby regeneration for src/app/sidebar/components and
side-effect barrel updates under src/stores/{auth,chat,sidebar,user},
plus package-lock.json from npm install (required for lint/typecheck).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-16 10:30:21 +08:00
admin 1449acd6c9 chore(barrels): regenerate barrel files via barrelsby
- Fix chat components barrel to properly export all component modules
- Remove interceptor exports from API services barrel
- Regenerate store barrel files (auth, chat, sidebar, user) using barrelsby
2026-06-15 17:53:15 +08:00
admin b9315c9f8b refactor(chat): synchronize guest chat quota updates for messages and images 2026-06-15 17:47:35 +08:00
admin 31f2433c4b refactor: auto-init guest chat quota on first read, clean up logs
- Remove unused `quotaWarningThreshold` and `warningThreshold` getter from `GuestChatQuota` DTO
- Apply get-or-init pattern in `ChatStorage.getGuestDailyChatQuota` and `getGuestTotalQuota`: when no existing value, initialize with DTO defaults (`threshold` = max per day, `totalQuotaDefault`) and return the seeded data
- Fall back to original `null` result if initialization write fails
- Consolidate logging strategy: drop per-actor trace logs in `chat-machine.ts`, keep business-decision logs in 3 assign actions, move all actor ENTRY/API/DONE chains to `chat-machine.actors.ts` and helper load logs to `chat-machine.helpers.ts`
2026-06-15 17:39:50 +08:00
admin fa694af723 docs(plan): add chat state machine refactor design
Update implementation_plan.md with a detailed refactor plan that splits
`chatInitActor` into two independent actors (`loadQuotaActor` +
`loadHistoryActor`) and redesigns the history loading flow to follow
local → network → save semantics so the UI sees local data first,
then network data.

Key changes outlined in the plan:
- Add new events: `ChatQuotaLoaded`, `ChatHistoryLocalLoaded`,
  `ChatHistoryNetworkLoaded`, `ChatHistorySyncDone`
- Remove dead-code `ChatInit` event
- Extend `ChatState` with `quotaLoaded` and `historyLoaded` flags
- Use an `always` barrier in `guestSession.initializing` and
  `userSession.initializing` so both tasks must complete before
  transitioning to `ready`
- Guest init runs `loadQuota` + `loadHistory` in parallel; non-guest
  init runs `chatWebSocket` + `loadHistory` as independent tasks

Also adds `implementation_plan` to .gitignore.
2026-06-15 17:05:32 +08:00
admin 1f3980d461 chore(chat): refactor chat init into separate quota and history actors
Split `chatInitActor` into `loadQuotaActor` (guest quota fetch) and `loadHistoryActor` (local → network → save sync), and add `quotaLoaded` / `historyLoaded` state flags so the UI can display loading status during the new local-first history hydration flow. Also drop the now-unused `ChatInit` event and pipe Next.js stdout/stderr to a persistent log file in the post-receive hook for easier troubleshooting.
2026-06-15 16:21:40 +08:00