# useDocyrusPivotCalendar URL: /docs/native/hooks/use-docyrus-pivot-calendar 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 ```bash pnpm dlx @docyrus/cli add @docyrus/rn-hooks-use-docyrus-pivot-calendar ``` **Dependencies:** - [@docyrus/api-client](https://www.npmjs.com/package/@docyrus/api-client) - [@tanstack/react-query](https://tanstack.com/query/latest) - [date-fns](https://www.npmjs.com/package/date-fns) A 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]@` (`YYYY-MM` for the year view) over a `dateRange` covering the active period. - With `groupBy`, a second matrix entry adds `groupLabel:` (plus `groupId:` when `idField` is set). The response is mapped into `cells` + `groups`, and `pivotCalendarProps` is ready to spread onto the native [rn-pivot-calendar](/docs/native/docyrus/pivot-calendar). It needs an authenticated `RestApiClient` and a `QueryClientProvider` above it. Only the first **2** measures are requested, same as web. ## Usage ```tsx 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(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 ; } ``` ## 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 (`...()`) 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) => 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:::pivot-calendar`. `true` / `'session'` is in-memory for the JS runtime. `'local'` uses the store registered with `` / `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 ` = `; without it, they use `rel_/ =