Components

Log Activity Form

A presentational multi-tab "log activity" composer — comment, email, call, meeting, task, and status — with every tab rendered inline, wired to Docyrus via the useDocyrusLogActivity hook.

Client Only

Installation

pnpm dlx @docyrus/cli add @docyrus/ui-log-activity-form
Required Packages(4 packages)
pnpm add @tanstack/react-form @tanstack/react-query motion sonner
UI Primitives(11 components)
npx shadcn@latest add badge button calendar command input label popover scroll-area select separator textarea

Overview

LogActivityForm is a presentational component (it owns no network I/O). A tab bar switches between six surfaces and each one renders its form inline — no dialog, no dropdown-triggered form. Every tab reuses the real Docyrus components / form-fields:

TabInline surface
CommentCommentsPanel (threaded)
EmailEmailComposer (send-only)
Statusinline StatusFormField (status list + sub-status / notes / follow-up date, no popover)
Tasksubject + status + priority + assignee + due date + description form-fields
Call / Meetingsubject + event type + start / end + owner + description form-fields

Wire it to a Docyrus record with useDocyrusLogActivity — the hook owns ALL I/O (option fetches, the per-tab create mutations, the two-call status update, and an embedded email composer) and returns a spreadable logActivityProps bag. This mirrors the EmailComposer / useDocyrusEmailComposer split.

Usage

import { LogActivityForm } from '@docyrus/ui/components/log-activity-form';
import { useDocyrusLogActivity } from '@docyrus/ui/library/hooks/use-docyrus-log-activity';
import { ContactActivityPanel, useDocyrusContactActivity } from '@docyrus/ui/components/contact-activity-panel';

function RecordActivity({ client, recordId }) {
  // One hook feeds the log form (all I/O).
  const { logActivityProps } = useDocyrusLogActivity({
    client,
    appSlug: 'base',
    dataSourceSlug: 'organization',
    recordId,
    taskRelationSlug: 'organization',   // per-tenant back-relation for task/event linking
    statusFieldSlug: 'status',
    callEventTypeName: 'Call',          // resolve the call/meeting event type by name
    meetingEventTypeName: 'Meeting'
  });

  // A sibling hook feeds the timeline. Both share the record-scoped query prefix,
  // so logging on the form auto-refreshes the panel — no manual refetch wiring.
  const { panelProps } = useDocyrusContactActivity({
    client, appSlug: 'base', dataSourceSlug: 'organization', recordId,
    taskRelationSlug: 'organization',
    sources: { audit: true, comments: true, tasks: true, statusUpdates: true }
  });

  return (
    <>
      <LogActivityForm {...logActivityProps} />
      <ContactActivityPanel {...panelProps} />
    </>
  );
}

API Reference

Every prop is optional — a bare <LogActivityForm /> renders the tab shell with empty surfaces. In practice you spread logActivityProps (see the hook), which fills all of these.

Shell

PropTypeDefaultDescription
activityTypesLoggableActivityType[]all sixWhich tabs to show (order preserved).
activeTypeLoggableActivityType—Controlled active tab.
defaultActivityTypeLoggableActivityTypefirst tabUncontrolled initial tab.
onTypeChange(type: LoggableActivityType) => void—Fired on tab change.
disabledbooleanfalseDisable every surface.
classNamestring—Root class.

Comment tab

PropTypeDescription
commentsDocyrusComment[]Thread source.
usersCommentUser[]Users for @ mentions / avatars.
currentUserCommentUserThe authoring user.
onCreateComment(payload: LogActivityCommentPayload) => void | Promise<void>Create / reply.
onDeleteComment(commentId: string) => void | Promise<void>Delete.
isCommentsLoading / isCreatingCommentbooleanPending flags.

Email tab

PropTypeDescription
emailComposerPropsPartial<EmailComposerProps>Spread onto the inline EmailComposer (from useDocyrusEmailComposer).
onSendEmail() => void | Promise<void>Send handler (the tab wraps it with a toast).
isSendingEmailbooleanPending flag.

Status tab

PropTypeDescription
statusFieldIField | nullThe record's status field (field-status / field-select).
statusEnumOptionsEnumOption[]Status options.
statusInitialValuesRecord<string, unknown>Current status + companion values, keyed by field slug.
onSubmitStatus(input: LogStatusInput) => void | Promise<void>Submit (two-call in the hook).
isSubmittingStatus / isStatusLoadingbooleanPending / loading flags.

Task tab

PropTypeDescription
taskStatusOptions / taskPriorityOptionsEnumOption[]Task enum options.
taskUsersEnumOption[]Assignee options ({ id, name, icon }).
onSubmitTask(input: LogTaskInput) => void | Promise<void>Submit.
isSubmittingTaskbooleanPending flag.

Call / Meeting tabs

PropTypeDescription
eventTypesEnumOption[]Event type options.
eventUsersEnumOption[]Owner options.
callEventTypeId / meetingEventTypeIdstringPreset event-type id per tab.
onSubmitEvent(input: LogEventInput, kind: 'call' | 'meeting') => void | Promise<void>Submit.
isSubmittingEventbooleanPending flag.

Type Exports

TypeDescription
LogActivityFormPropsProps for the presentational form.
LoggableActivityType"comment" | "email" | "call" | "meeting" | "task" | "status_update"
LogActivityCommentPayloadComment submit payload ({ content, parent_id?, mentions? }).
LogTaskInputTask submit payload.
LogEventInputCall / meeting submit payload.
LogStatusInputStatus submit payload.

On this page