useDocyrusPivotCalendar
PivotCalendar backed by a Docyrus data source. Aggregates per day or month in the database through a pivot matrix, optionally grouped by a relation, and turns a tapped value into a ready-to-run drilldown query.
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-hooks-use-docyrus-pivot-calendarpnpm add @docyrus/api-client @tanstack/react-query date-fnsA straight port of the web hook, with the same signature. It sends a pivot.matrix + calculations request to GET /v1/apps/{appSlug}/data-sources/{dataSourceSlug}/items through TanStack Query:
- The date axis is
bucket:to_char[YYYY-MM-DD]@<dateField>(YYYY-MMfor the year view) over adateRangecovering the active period. - With
groupBy, a second matrix entry addsgroupLabel:<labelField>(plusgroupId:<idField>whenidFieldis set).
The response is mapped into cells + groups, and pivotCalendarProps is ready to spread onto the native PivotCalendar. It needs an authenticated RestApiClient and a QueryClientProvider above it. Only the first 2 measures are requested, same as web.
Usage
import { useState } from 'react';
import { useDocyrusClient } from '@docyrus/signin/react-native';
import { PivotCalendar } from '@/components/docyrus-native/pivot-calendar';
import {
useDocyrusPivotCalendar,
type DocyrusPivotDrilldownQuery
} from '@/hooks/docyrus-native/use-docyrus-pivot-calendar';
const toHours = (seconds: number) => seconds / 3600;
export function TimeEntriesCalendar() {
const client = useDocyrusClient();
const [drilldown, setDrilldown] = useState<DocyrusPivotDrilldownQuery | null>(null);
const { pivotCalendarProps, buildDrilldownQuery } = useDocyrusPivotCalendar({
client: client!,
appSlug: 'base',
dataSourceSlug: 'time_entry',
dateField: 'date',
measures: [
{ id: 'logged', label: 'Logged', field: 'duration', func: 'sum', transform: toHours, formatValue: v => `${v.toFixed(1)}h`, color: '#10b981' },
{ id: 'billable', label: 'Billable', field: 'duration_billable', func: 'sum', transform: toHours, formatValue: v => `${v.toFixed(1)}h`, color: '#6366f1' }
],
groupBy: { field: 'record_owner', label: 'User', labelField: 'name', idField: 'user_id' },
persistState: true,
// `drilldown.filters` / `columns` / `orderBy` → fetch the underlying records.
onCellClick: info => setDrilldown(buildDrilldownQuery(info))
});
return <PivotCalendar {...pivotCalendarProps} />;
}API Reference
Options
| Option | Type | Default | Description |
|---|---|---|---|
client | RestApiClient | — | Required. Authenticated Docyrus API client. |
appSlug | string | — | Required. App slug of the data source. |
dataSourceSlug | string | — | Required. Data source slug. |
dateField | string | — | Required. Date field that is bucketed per day or month (e.g. created_on, due_date). |
measures | DocyrusPivotMeasure[] | — | Required. Measures to aggregate. Only the first 2 are requested and rendered. |
groupBy | DocyrusPivotGroupBy | — | Optional grouping dimension (relation, user or select field). |
columns | string | — | Extra columns segment for the request. Defaults to a relation spread (...<groupBy.field>(<labelField>)) or id. |
filters | unknown | — | Filters applied to the aggregated records. They are also merged into the drilldown query. |
defaultView | TPivotCalendarView | 'month-calendar' | Initial view. |
view | TPivotCalendarView | — | Controlled view. |
onViewChange | (view: TPivotCalendarView) => void | — | Called when the view changes. |
defaultDate | Date | new Date() | Initial reference date. |
date | Date | — | Controlled reference date. |
onDateChange | (date: Date) => void | — | Called when the reference date changes. |
hideViewSwitcher | boolean | — | Pass-through to PivotCalendar. |
hideSidebar | boolean | — | Pass-through to PivotCalendar (hides the group filter sheet). |
visibleViews | TPivotCalendarView[] | — | Pass-through to PivotCalendar. |
enabled | boolean | true | Enables or disables the query. |
staleTime | number | 30000 | TanStack Query staleTime (ms). |
showEmptyCells | boolean | true | When false, sends pivot.hideEmptyRows: true. |
onCellClick | (info: IPivotCalendarCellClick<PivotRow>) => void | — | Fires when a value is tapped. Pair it with buildDrilldownQuery. |
persistState | boolean | { storage?: 'session' | 'local'; key?: string } | — | Persists the uncontrolled view and focused date under docyrus:view-params:<appSlug>:<dataSourceSlug>:pivot-calendar. true / 'session' is in-memory for the JS runtime. 'local' uses the store registered with <DocyStorageProvider> / setDocyLocalStore() and survives restarts. Controlled view / date always win. |
DocyrusPivotMeasure
| Field | Type | Description |
|---|---|---|
id | string | Stable id; also the calculation name in the response. |
label | string | Visible label. |
shortLabel | string | Compact label for headers. |
field | string | Field slug to aggregate ('id' for count). |
func | 'sum' | 'count' | 'avg' | 'min' | 'max' | Aggregation function. |
transform | (value: number) => number | Applied to the API value (e.g. seconds → hours). |
formatValue | (value: number) => string | Cell formatter. |
color | string | Accent colour. |
description | string | Shown in the day sheet. |
DocyrusPivotGroupBy
| Field | Type | Description |
|---|---|---|
field | string | Grouping relation / select field slug. |
label | string | Label for the filter sheet and the grid's group column. |
labelField | string | Sub-field used as the group label. Default 'name'. |
idField | string | Non-join sub-field used as a stable group id (e.g. 'user_id' for users). With it, drilldown filters use <field> = <id>; without it, they use rel_<field>/<labelField> = <label>. |
filters | unknown | Filters on the group dimension's CTE. |
toGroup | (row: PivotRow) => Partial<IPivotCalendarGroup> | Avatar / colour override per group. |
Result
| Field | Type | Description |
|---|---|---|
pivotCalendarProps | PivotCalendarProps<TData> | Spread onto <PivotCalendar /> (remote mode). |
cells | IPivotCalendarRemoteCell[] | Mapped cells. |
groups | IPivotCalendarGroup[] | Groups found in the response, sorted by label. |
measures | IPivotCalendarMeasure<TData>[] | Component measures. |
view / setView | TPivotCalendarView / (view) => void | Active view. |
selectedDate / setSelectedDate | Date / (date) => void | Reference date. |
isLoading | boolean | First load in flight. |
error | Error | null | Query error. |
refetch | () => void | Refetch the pivot. |
buildDrilldownQuery | (info: IPivotCalendarCellClick<TData>) => DocyrusPivotDrilldownQuery | Converts a tap into filters (date between + group + caller filters), columns and orderBy, ready for /items. |
DocyrusPivotDrilldownQuery
| Field | Type | Description |
|---|---|---|
appSlug / dataSourceSlug / dateField | string | Source identity. |
groupField / groupLabel | string / string | null | Group dimension and the tapped group's label. |
bucketStart / bucketEnd | Date | Bucket range. |
bucketStartIso / bucketEndIso | string | Same range as ISO strings. |
measureField / measureFunc | string / TPivotCalendarAggregate | Tapped measure source. |
measure / measureValue / measureFormatted | IPivotCalendarMeasure<PivotRow> / number / string | Tapped measure and value. |
filters | DocyrusPivotFilterGroup | { combinator: 'and', rules }. |
columns | string | Suggested columns. |
orderBy | string | <dateField> DESC. |
Type Exports
| Type | Description |
|---|---|
UseDocyrusPivotCalendarOptions | Hook options. |
UseDocyrusPivotCalendarResult<TData> | Hook result. |
DocyrusPivotMeasure | Measure descriptor. |
DocyrusPivotGroupBy | Grouping descriptor. |
DocyrusPivotFilterRule / DocyrusPivotFilterGroup | Drilldown filter shapes. |
DocyrusPivotDrilldownQuery | buildDrilldownQuery result. |
PivotRow | Record<string, unknown>. |
useDocyrusMapView
Map backed by a Docyrus data source. Detects the location field and builds markers from logos, icons or the default pin, with clustering, a viewport filter, basemaps and drag-to-move with reverse geocoding.
useDocyrusPivotFilter
Connects a Docyrus data source to a native PivotFilter strip. It detects the field type, runs a pivot aggregate query, builds pill items and date buckets, and emits filter rules. DocyrusPivotFilterGroup stacks several strips that cross-filter each other.