# rn-contact-activity-panel URL: /docs/native/docyrus/contact-activity-panel Typed activity timeline for a contact or record, with category tabs, a type filter, relationship summary, upcoming tasks, an emit-only Add menu and a detail sheet with replies and reactions. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-contact-activity-panel ``` **Dependencies:** - [@shopify/flash-list](https://www.npmjs.com/package/@shopify/flash-list) - [@tanstack/react-query](https://www.npmjs.com/package/@tanstack/react-query) - [react-native-reanimated](https://www.npmjs.com/package/react-native-reanimated) - [react-native-gesture-handler](https://www.npmjs.com/package/react-native-gesture-handler) The panel stacks these regions: 1. **Header** (`contact`, `showHeader`, `headerActions`). 2. **Category tabs** (All / Communication / Tasks / Updates) with counts, plus a filter button that opens the grouped type filter in an action sheet. 3. **Summary row**: last contacted, next activity, open task count, the Ask Docy button (`renderAiAssistant`) and the **+** Add menu (`addActions` + `onAddActivity`). 4. **Upcoming** tasks and meetings. Task checkboxes call `onToggleUpcomingTask`. 5. **Timeline**: calendar day groups (Today, Yesterday, This week, Last week, This month, Last month, Earlier this year, Last year, Older) on a continuous rail. Communication types render as cards (title, preview, time range, attachment and reply counts, participant avatars). Tasks and updates render as one-line rows with an attachment marker. The list is virtualised with FlashList. 6. **Detail sheet** (large action sheet): type chip, time range and full timestamp, a **Details** block of the activity's own metadata (call direction / duration, meeting location, email recipients, task status / priority / due date, …), participants, body, summary, key points, follow-ups (`onToggleFollowUp`), **document cards** (image thumbnails, per-type icons, tap to open), related records, a reaction row, the reply thread for comments, the primary action and Delete. The Add menu emits `onAddActivity(type)`. Pass **`renderAddForm`** as well and the panel opens your form for the picked type in its own sheet — typically a `LogActivityForm` scoped with `activityTypes={[type]}`. Call `close()` after a successful submit. With a single `addActions` entry the trigger skips the menu and opens the form directly. ### Timestamps Timeline timestamps count up while the event is recent and become a date once it isn't: `now → 5m → 3h → 2d → 3w → 21 Sep → 21 Sep 2025`. The units are translation keys (`ui.contactActivity.time.*`) and the absolute form uses the device locale. Connect it to Docyrus with [`useDocyrusContactActivity`](/docs/native/hooks/use-docyrus-contact-activity), which is also re-exported from this component. ## Usage ```tsx import { ContactActivityPanel, useDocyrusContactActivity } from '@/components/docyrus-native/contact-activity-panel'; function ContactTimeline({ client, contact, meId }) { const [logType, setLogType] = useState(null); const { panelProps } = useDocyrusContactActivity({ client, appSlug: 'base', dataSourceSlug: 'contact', recordId: contact.id, relationSlug: 'contact', currentUserId: meId }); return ( ); } ``` Without `maxHeight` the panel is `flex-1` and fills its parent, so give the parent a bounded height (a screen, or a sized `View`). Do not nest it in a vertical `ScrollView`. Pass `maxHeight` for a fixed-height panel. ### Replies and reactions For `comment` activities the detail sheet loads replies with `onLoadReplies(activityId)` and renders them with the team-chat [rn-team-chat-channel](/docs/native/docyrus/team-chat-channel) (as on web): `@` mentions, emoji, attachments and — with `dataSources` + `onSearchEntity` — entity links. Submitting calls `onCreateComment({ content, parent_id, attachments, linked_entities, mentioned_user_ids, hashtags })`. `parent_id` is the raw comment id taken from `metadata.__sourceId`. Own replies can be deleted after confirmation (`onDeleteComment`). With `onToggleReaction`, the sheet shows reaction chips for the activity and for each reply. Tap the smiley / `+` button, or long-press a reply, to pick one of the preset emoji (or **More** for the full EmojiPicker). `targetId` is the reply id, or the activity's `metadata.__sourceId` (falling back to its `id`). Editing replies is not offered (the panel has no update callback — same as web). ## API Reference ### ContactActivityPanelProps | Prop | Type | Default | Description | |------|------|---------|-------------| | `activities` | `ContactActivity[]` | - | Timeline items. Sorted newest first by `created_on` (required) | | `currentUser` | `ChatUser` | - | Signed-in user (own replies, delete permission) | | `users` | `ChatUser[]` | - | Users for avatars, names and mentions | | `contactName` | `string` | `contact.name` | Name used in the empty state | | `isLoading` | `boolean` | `false` | Show the loading skeleton | | `isCreatePending` | `boolean` | `false` | Pending state of the reply composer | | `isDeletePending` | `boolean` | `false` | Pending state of the delete confirmations | | `onDeleteActivity` | `(activityId: string) => void \| Promise` | - | Enables Delete (after confirmation) on the current user's activities | | `onCreateComment` | `(payload: CreatePostPayload) => void \| Promise` | - | Post a reply to a comment activity | | `onDeleteComment` | `(commentId: string) => void \| Promise` | - | Delete an own reply | | `onToggleReaction` | `(targetId: string, emoji: string) => void \| Promise` | - | Toggle a reaction on an activity or reply | | `onUploadFile` | `(file: NativeFile) => Promise