Inbox and conversations
- Direct conversations. Open existing one-to-one threads or start a conversation by selecting a user in the new-message modal. Existing channels are reused; new channels are created when needed.
- Creator inbox tabs. Creators have Priority, General, and Message Lists views. Non-creators use the General conversation view.
- Priority classification. A thread enters Priority when its user has the backend featured flag or it has an unread tip. Broadcast threads go into Message Lists. Sorting places recent conversations first.
- Conversation search. Search the inbox through a debounced API query. New-recipient and participant searches also debounce input and cancel the previous request.
- Conversation previews. Rows show the person's name, avatar or fallback icon, recent text or a Media label, unread count, and selected-thread highlighting.
- Identity and fan badges. Display creator verification, qualifying subscriber indicators, and normalized fan badges with tooltips in the list and conversation header.
- Tip and reply indicators. Mark unread tips and pending guaranteed replies in conversation rows.
- Unread counts. Track conversation and tab counts plus the shared app message count. Opening a thread clears its local unread count and unread-tip indicator.
- Online presence. Show online/offline indicators from WebSocket membership data, both in inbox rows and in the selected direct conversation.
- Conversation history. Fetch stored messages for the selected channel. Group them by Today, Yesterday, or a calendar date; show local timestamps and sender avatars where the sender changes.
- Live updates. Receive messages through the shared WebSocket service. Append messages in the active thread, refresh inbox ordering, and increase unread counts for other threads. The service contains reconnect handling.
- Deep links and return flows. Select a conversation through the
userquery parameter, a route/queryidfor payment return handling, or router state carrying a user key or group ID. - Profile navigation. Open the selected user's profile from the conversation header.
- Responsive layout. Desktop displays the list and thread together. Mobile selection opens the thread, with a back control to return to the list.
- Loading and empty states. Show inbox and conversation loaders, a no-messages state, and an empty-automation state.
Source: inbox and thread logic, WebSocket service.
Message composition and sending
- Text, attachments, or both. Send text-only, attachment-only, or mixed messages. Empty and whitespace-only text without attachments or shared content does not send.
- Growing text area. The composer grows as text fills it, up to four rows. Message URLs render as clickable links in the thread.
- Emoji picker. Insert the chosen emoji at the current cursor position. Selecting an emoji or clicking outside closes the picker.
- First-name personalization. Broadcast composition offers an Insert First Name action that inserts
[First Name]at the cursor. The automated-message text field also exposes first-name insertion. - Local sending queue. Add an outgoing message locally, upload attachments, then send the completed payload. The UI tracks submission and upload progress and resets composition after sending.
- Navigation protection during sending. Pending queue entries prevent route deactivation, and switching to another conversation is restricted while the queue is occupied. This protection concerns queued sends, not every unsent draft.
Source: composer and send pipeline, route protection.
Media and file attachments
- Images, videos, audio, and other files. The main composer classifies selected files into these four types. Generic files show their filename and formatted size.
- Multiple attachments. Select multiple files, inspect previews, and remove individual items before sending.
- Images. Compress selected images, create thumbnails, and open sent or received images in a lightbox overlay.
- Video playback. Preview attached videos and play conversation videos in a player modal. Portrait video metadata controls the player presentation.
- Audio playback. Play uploaded audio and recorded voice messages. The composer has an audio preview that can be cleared before sending.
- Voice recording. Start, stop, cancel, and discard microphone recordings. Show elapsed recording time and a live waveform; a nonzero recording becomes an audio attachment.
- Downloads. Available recipient media has download actions. In the mobile app, downloads pass to the native bridge; browser downloads use a file download flow.
- Upload feedback and moderation. Track image and file upload progress. Images flagged by the upload service open a restricted-content carousel. Upload errors return user-facing feedback.
- Mobile file selection. File inputs integrate with the mobile bridge. The automated-message attachment component also handles files supplied by the native app.
- Media presentation. Images use lazy loading and mobile image optimization. Media elements use the shared right-click restriction directive where configured.
Source: selection and previews, uploads.
Paid attachments and free previews
- Set an unlock price. With the Lock Message permission and at least one attachment, open the pricing modal and set the price recipients pay to view the attachment bundle.
- International prices. The main pricing modal opens the currency conversion component. It stores adjusted international prices alongside the base dollar price in the outgoing message.
- Optional free preview. Add one preview item separately from the locked attachments. Recipients see a Free Preview area before paying.
- Drag and reorder. Reorder attachments and move eligible media between the paid area and the free-preview area, subject to item limits.
- Shared-link preview restriction. Store, portfolio, and event share links cannot be moved into the free-preview area while the message has a positive unlock price.
- Remove the lock. Clearing the price removes international-price data and moves the free preview back into the regular attachment list.
- Locked presentation. Paid images have blurred or locked URLs generated by the upload flow. The thread displays a Paid label, price, and an unlock action for qualifying received locked messages.
- Purchase and return. Unlocking sends message ID, channel, timestamp, sender, and amount to the shared payment flow, which returns to Messages. The unlock action checks delegate-user permission.
Source: pricing and currencies, preview constraints and unlocking.
Tips and guaranteed replies
- Tip with a direct message. Eligible direct conversations with creators expose a tip amount panel. Tips can include text and media and use the shared checkout flow.
- Preset and custom amounts. Generate suggested amounts from the minimum tip and multipliers of 1, 5, 10, 20, and 50. Support a custom amount with numeric, minimum, and currency-range validation.
- Local currency. Display converted suggestions, a currency symbol, and local prices; convert the tip to its USD base amount for payment.
- Tip receipts in the thread. Render the amount and distinguish an ordinary tip from a guaranteed-reply payment.
- Guaranteed-reply offer. Backend validation supplies the offer flag and minimum qualifying tip. A modal explains the offer and lets the sender add a tip or send without the guarantee.
- Refund terms displayed to the sender. The offer copy says that a qualifying tip is automatically refunded within seven days if the creator does not reply. Refund processing is a backend/payment responsibility.
- Pending-reply fulfillment. A creator reply to a pending guaranteed-reply message calls the redemption endpoint. On successful redemption, clear the pending indicator, display the credited-wallet notice, and send the reply.
- Composition restrictions. Tip controls apply to direct creator conversations, rather than broadcast or follower-list sends. A positive attachment price or inserted share content disables tip selection. Delegate mode has additional permission handling.
Source: offer and redemption, tip amounts and checkout.
Free DM credits and pay-per-message
- Creator-specific validation. Fetch the selected recipient's DM price, free-message allowance, unlimited allowance flag, guaranteed-reply status, and currency data.
- Credit status. Display remaining free messages, Unlimited where applicable, or the paid DM price when no free messages remain.
- Consume free credits. When a priced creator conversation still qualifies for a free message and has no attached tip, call the consume-credit endpoint and update the allowance before sending.
- Pay after credits run out. Route the message and its attachments to pay-per-message checkout when the recipient charges for DMs and the finite free allowance is exhausted.
- Combined DM price and tip. A combined checkout payload carries the DM charge and tip separately while charging their total. Preserve message text, media, channel, and guarantee context.
Source: credit-aware send decisions, paid DM payloads.
Message lists and broadcast sending
- Create a named message list. Select individual users or audience groups, then enter a list name and optionally upload a cropped list icon.
- Two audience types. Lists can contain individual users or predefined/subscription groups. The selection UI prevents mixing those two types in one list.
- Predefined audiences. Choose Fans and Subscribers, Current Fans, All Current Subscribers, Previously Paid Subscribers, Top 20 Spenders, or Prior Paid DM Users. The frontend maps display labels to backend audience keys.
- Subscription audiences. Select subscription-plan audiences returned by the new-chat API. Preserve the plan ID when creating or editing the group list.
- Bulk conversation view. Show saved message lists with their name, icon, recipient details, unread count, and recent activity. Select a list to open its broadcast history.
- Broadcast delivery. Send text and attachments through the public/broadcast WebSocket action using the list's broadcast ID.
- Edit list details. Rename a list and update its icon through the list-details modal.
- Edit recipients. Search current and available participants, add or remove users or audience groups, and save the changes. The selected conversation reflects the updated participants.
- Recipient count. Show the selected list's recipient count in the thread header; selecting it opens participant editing.
- Delete a list. Confirm deletion in a modal, remove it through the API, and refresh the message-list view.
- Personalized broadcast text. Insert the first-name token into list messages. Recipient expansion and delivery are backend responsibilities.
Source: new lists and audience selection, participant editing.
Automated messages
- Automation management. An Automated Messages tab lists each configured event type and its message text, with add, edit, and delete actions.
- Four configured triggers. Fan Registers, Fan Purchases Subscription, Fan Purchases Content Post, and Fan's Birthday. The registration label maps to the backend
FOLLOW_MESSAGEtype. - One configuration per trigger. Disable event types already present in the automation list. Editing keeps the existing event type fixed.
- Required text. Event type and message text are required. Text has a 1,000-character maximum and supports first-name insertion.
- Image and audio attachments. The automation attachment component supports image uploads, audio uploads, voice recording, and audio preview. Its current file classifier does not accept newly selected video or generic files.
- Paid automated attachments. Set a lock price with the automation's separate price modal and optionally provide a free preview. A positive price requires at least one main attachment.
- Edit existing media. Restore existing paid/main and free-preview attachments. Existing attachments are marked as patched and reused without uploading them again.
- Save and refresh. Create through POST, update through PUT, and delete by event type through DELETE. Refresh the table and show success or error feedback.
- Cancel and reset. Closing clears form values, attachments, pricing, and audio previews, and aborts an active recording.
Source: triggers and form validation, automation editor, accepted automation media.
Permissions, safety, and white-label behavior
| Capability | Availability in the frontend |
|---|---|
| Enter Messages | The lazy-loaded route uses authentication, permission, and creator-approval guards. Delegate access references Send Reply to Direct Messages. The Messages tab also checks its permission key. |
| Send or start a message | The new-message action and composer require the profile's 18-or-older flag. Younger users see an age notice and a customer-support link. |
| Lock attachments | Requires Lock Message permission in the main composer, attached items, and a compatible composition state. |
| Manage automated messages | Requires Automated Messages permission. On a white-label site, the tab additionally requires the profile's host-owner flag. |
| Insert creator content | Store, portfolio, and event actions display for creator accounts. |
| Block a user | The main TopFan site exposes Block User from inbox and direct-thread menus. It opens a confirmation dialog and refreshes the inbox. These menus are hidden on white-label sites. |
| Hidden or exclusive creator | On the main site, backend is_hidden validation hides composition and displays the creator-unavailable notice. White-label conversation behavior bypasses that particular display condition. |
| White-label conversation list | Show the list on the main site, to the tenant owner, or when tenant DM settings allow it. Otherwise, select the tenant owner as the default conversation target. |
| Start a chat on a tenant site | The New Message action is available to the tenant owner rather than other tenant visitors. Explicit incoming chat targets are respected, and self-targets are cleared. |
| Tenant context | Use white-label configuration for owner identity and waveform color; outgoing messages carry the white-label owner ID. Share URLs use environment configuration. |
| Delegate purchase actions | Attachment unlocking and the subscription purchase helper check delegate-user permission before starting payment. Tip handling also has delegate-specific conditions. |
Source: route guards, composer and tab permissions, tenant targeting.
Limits and validation
| Item | Current check |
|---|---|
| Main attachments | Five items in the regular/paid attachment area. This check also applies when the message is free. Store and event links share this capacity. Portfolio insertion does not call the same capacity check. |
| Free previews | One item in the separate free-preview area. |
| File size | The picker checks the first selected file against 512 MB and displays a video-size error if exceeded. It does not check every selected file individually in this method. |
| Main unlock price | The main pricing modal disables Save below $1 or above $10,000 and uses two-decimal input formatting. |
| Automation unlock price | The separate V2 modal uses a keypress limiter intended to cap entry at $1,000. It does not use the main modal's $1-to-$10,000 Save validation or currency-adjustment control. |
| Automated message text | Required, with a maximum of 1,000 characters. |
| Message list name | Required, with a maximum of 25 characters. |
| List membership | An individual-user list requires at least two selected users. An audience-group list requires at least one selected group. Participant editing preserves these minimums. |
| Tips | Suggested amounts use a default minimum of $1 or the guaranteed-reply minimum. Custom amounts are checked against numeric format, qualifying minimums, and currency-derived bounds. |
| Empty messages | Require nonblank text, an attachment, or share content. |
Source: main pricing validation, automation pricing limiter, list form limits.
Implementation boundaries and related flows
- Older-message scrolling is inactive. The template wires an upward-scroll event, but
onUp()has its history-fetch call commented out. Initial history retrieval exists; working infinite history loading is not established by this implementation. - Reporting has a helper only.
reportUser()opens the shared chat-report dialog, but the messages template has no call to it. The visible moderation action is Block User. - Dispute messages can be displayed. The thread recognizes dispute payloads and renders the product image, product name, price, and reason. It does not expose a dispute-creation form here.
- Subscription helpers exist. The container can fetch a creator's plans, open a subscription picker, and launch subscription checkout. The current template does not call these helpers, so they are not counted as an exposed Messages action.
- Welcome-message editing is separate. The profile welcome-message editor lives under Edit Preference. Its preview, enable/disable state, and upload controls are outside this module. The automation trigger labeled Fan Registers is part of Messages.
- Purchase history is separate. Wallet's purchased-direct-messages view tracks purchased messages and redirects into a thread. Messages initiates attachment checkout and displays message content.
- Feed-sharing copy is not evidence of a feature. Constants include a label for adding feed content, but this composer exposes store, portfolio, and event pickers. No separate feed-content picker is wired in its template.
- No exposed message editing or deletion. The reviewed template has no per-message edit, delete, or unsend action. Message-list and automation deletion are separate supported operations.
- Backend-driven execution. Automated trigger timing, audience resolution, guaranteed-reply refunds, payment settlement, and durable message delivery are not implemented by this frontend module.
Source: inactive scroll handler, report helper, actual UI bindings.
Source map
- Main page and conversation behavior
messages.routes.tsandcomponents/message-container/cover inboxes, composition, media, payments, tenant rules, and live events.- List creation and editing
components/new-message-model/,components/edit-participants-modal/, andconstants/messages.constant.tsdefine list fields, membership editing, and audience mappings.- Pricing and automation
components/message-price-model/,components/message-price-model-v2/,components/automated-message-modal/, andcomponents/image-audo-message/implement the two pricing flows and the automation editor.- Shared dependencies
services/chat.service.ts,shared/services/audio-recording.service.ts, and the shared store, portfolio, event, preview, and video-player components supply messaging integrations.