LogActivityForm
Presentational multi-surface activity composer with Comment, Email, Call, Meeting, Task and Status tabs, each reporting its own typed submit callback.
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-log-activity-formpnpm add react-native-reanimated @shopify/flash-listA scrollable tab bar switches between six surfaces rendered inline:
| Tab | Surface | Callback |
|---|---|---|
| Comment | CommentsPanel (mentions, replies, delete) | onCreateComment, onDeleteComment |
Native EmailComposer, or the renderEmailComposer slot | onSendEmail | |
| Call / Meeting | Subject, type, start, end, owner, description | onSubmitEvent(input, 'call' | 'meeting') |
| Task | Subject (required), status, priority, assignee, due date, description | onSubmitTask |
| Status | Inline DocyFieldStatus with sub-status, notes and follow-up date | onSubmitStatus |
The form owns no network I/O. Spread useDocyrusLogActivity(...).logActivityProps to connect it to Docyrus, or pass your own data and callbacks. Every submit shows a success or error toast through the native toast (mount a <Toaster />). A rejected callback keeps the draft so the user can retry.
Usage
import { LogActivityForm } from '@/components/docyrus-native/log-activity-form';
import { useDocyrusLogActivity } from '@/hooks/docyrus-native/use-docyrus-log-activity';
function LogActivity({ client, recordId }) {
const { logActivityProps } = useDocyrusLogActivity({
client,
appSlug: 'base',
dataSourceSlug: 'contact',
recordId,
relationSlug: 'contact',
callEventTypeName: 'Call',
meetingEventTypeName: 'Meeting'
});
return <LogActivityForm {...logActivityProps} defaultActivityType="call" />;
}Without the hook
<LogActivityForm
activityTypes={['task', 'call', 'comment']}
taskStatusOptions={[{ id: 'open', name: 'Open' }, { id: 'done', name: 'Done' }]}
taskUsers={[{ id: 'u1', name: 'Alice Johnson', icon: 'https://…/alice.png' }]}
onSubmitTask={input => api.createTask(input)}
onSubmitEvent={(input, kind) => api.createEvent({ ...input, kind })}
comments={comments}
users={users}
currentUser={me}
onCreateComment={({ content, parent_id, mentions }) => api.comment(content, parent_id, mentions)} />Email tab
The tab renders the native EmailComposer with emailComposerProps spread onto it (from/accounts, cc/bcc, @ mentions and / slash commands when they are present). useDocyrusLogActivity fills these props from its embedded useDocyrusEmailComposer. to, subject and body are controlled by emailComposerProps when their setters are passed, and keep local state otherwise. The body is email-safe HTML. Send needs a recipient, a subject and onSendEmail, and shows the success / error toast.
Pass renderEmailComposer to render your own surface instead. It receives the same emailComposerProps and the wrapped onSendEmail.
<LogActivityForm
{...logActivityProps}
renderEmailComposer={({ emailComposerProps, onSendEmail, isSendingEmail, disabled }) => (
<MyEmailComposer {...emailComposerProps} sending={isSendingEmail} disabled={disabled} onSend={onSendEmail} />
)} />API Reference
LogActivityFormProps
| Prop | Type | Default | Description |
|---|---|---|---|
activityTypes | LoggableActivityType[] | all six | Tabs to show, in this order |
activeType | LoggableActivityType | - | Controlled active tab |
defaultActivityType | LoggableActivityType | first tab | Uncontrolled initial tab |
onTypeChange | (type: LoggableActivityType) => void | - | Tab change callback |
className | string | - | Container classes |
disabled | boolean | false | Disable tabs and every surface |
comments | DocyrusComment[] | [] | Comment tab list |
users | CommentUser[] | - | Users for comment authors and mentions |
currentUser | CommentUser | - | Signed-in user (own comments) |
onCreateComment | (payload: LogActivityCommentPayload) => void | Promise<void> | - | Post a comment or reply |
onDeleteComment | (commentId: string) => void | Promise<void> | - | Delete a comment |
isCommentsLoading | boolean | - | Comment list skeleton |
isCreatingComment | boolean | - | Pending comment state |
emailComposerProps | Partial<LogActivityEmailComposerProps> | - | Props spread onto the Email tab EmailComposer |
onSendEmail | () => void | Promise<void> | - | Send handler for the Email tab |
isSendingEmail | boolean | - | Pending send state |
renderEmailComposer | (context: LogActivityEmailComposerContext) => ReactNode | - | Native-only: render your own Email tab surface |
statusField | IField | null | - | The record's field-status / field-select field |
statusEnumOptions | EnumOption[] | statusField.enums | Status options |
statusInitialValues | Record<string, unknown> | {} | Current status and companions, keyed by <slug> and __<slug>_secondary / _description / _followup_date |
onSubmitStatus | (input: LogStatusInput) => void | Promise<void> | - | Log a status change |
isSubmittingStatus | boolean | - | Pending status submit |
isStatusLoading | boolean | - | Status tab loading state |
taskStatusOptions | EnumOption[] | [] | Task status options (hidden when empty) |
taskPriorityOptions | EnumOption[] | [] | Task priority options (hidden when empty) |
taskUsers | EnumOption[] | [] | Assignee options (icon = avatar URL, hidden when empty) |
onSubmitTask | (input: LogTaskInput) => void | Promise<void> | - | Create a task |
isSubmittingTask | boolean | - | Pending task submit |
eventTypes | EnumOption[] | [] | Event type options (hidden when empty) |
eventUsers | EnumOption[] | [] | Owner options (hidden when empty) |
callEventTypeId | string | - | Preset event type for the Call tab |
meetingEventTypeId | string | - | Preset event type for the Meeting tab |
onSubmitEvent | (input: LogEventInput, kind: 'call' | 'meeting') => void | Promise<void> | - | Log a call or meeting |
isSubmittingEvent | boolean | - | Pending event submit |
LogActivityCommentPayload
| Field | Type | Description |
|---|---|---|
content | string | Markdown body ([@Name](mention://id) mention tokens) |
parent_id | string | Parent comment for replies |
mentions | string[] | Mentioned user ids |
LogTaskInput
| Field | Type | Description |
|---|---|---|
subject | string | Required |
statusId | string | null | Task status option id |
priorityId | string | null | Task priority option id |
ownerId | string | null | Assignee user id |
dueDate | string | null | Date-only YYYY-MM-DD |
description | string | null | Description |
LogEventInput
| Field | Type | Description |
|---|---|---|
subject | string | Required |
eventTypeId | string | null | Event type (calendar) id |
ownerId | string | null | Owner user id |
startDate | string | null | ISO datetime |
endDate | string | null | ISO datetime (must not be before the start) |
description | string | null | Description |
LogStatusInput
| Field | Type | Description |
|---|---|---|
value | string | Status option id (required) |
secondaryValue | string | null | Sub-status option id |
description | string | null | Notes |
followupDate | string | null | Date-only YYYY-MM-DD |
LogActivityEmailComposerContext
| Field | Type | Description |
|---|---|---|
emailComposerProps | Partial<LogActivityEmailComposerProps> | The props passed to the form |
onSendEmail | () => Promise<void> | Send wrapped with the success / error toast |
isSendingEmail | boolean | Pending send state |
disabled | boolean | The form's disabled |
LogActivityEmailComposerProps types to, cc, bcc (string[]), subject, body (HTML) and their on…Change setters, and lets every other EmailComposerProps key pass through to the tab's EmailComposer.
Components
| Component | Description |
|---|---|
LogActivityForm | Tab bar plus the six activity surfaces |
Type Exports
| Type | Description |
|---|---|
LogActivityFormProps | Props for LogActivityForm |
LoggableActivityType | 'comment' | 'email' | 'call' | 'meeting' | 'task' | 'status_update' |
LogActivityCommentPayload | Comment tab payload |
LogTaskInput | Task tab payload |
LogEventInput | Call / Meeting tab payload |
LogStatusInput | Status tab payload |
LogActivityEmailComposerProps | Email tab composer props |
LogActivityEmailComposerContext | Argument of renderEmailComposer |
LOGGABLE_ACTIVITY_TYPES | Constant: all six types in default order |
Breaking changes
The form was rewritten to match the web per-tab API.
- The single
onSubmit(payload: LogActivityPayload)was replaced by per-tab callbacks:onCreateComment,onDeleteComment,onSendEmail,onSubmitStatus,onSubmitTaskandonSubmitEvent.LogActivityPayloadis no longer exported. activityTypewas renamed toactiveType.activityTypesnow selects and orders the tabs.statusOptions: StatusOption[]was replaced bystatusField+statusEnumOptions+statusInitialValues.StatusOptionis no longer exported.isSubmitting,placeholderandsubmitLabelwere removed. Each tab has its own pending prop (isCreatingComment,isSendingEmail,isSubmittingStatus,isSubmittingTask,isSubmittingEvent) and translated button labels (ui.logActivity.*).- The Comment tab is a full
CommentsPanelinstead of a text box, and the tab icons are DocyrusIcons instead of emoji.
ListView
Feature-rich list with search, filters, sorting, list/grid display toggle, and pagination.
Map
Compound map on react-native-maps with markers, callouts, circles, polylines, polygons, marker clustering, and map-type, zoom, locate and search controls. Falls back to a card when the module is missing.