useDocyrusTenant
Tenant integration for Docyrus native apps. Fetches tenant preferences, builds dateUtils and numberUtils, and wires DateFormatProvider and NumberFormatProvider so every native component picks up the tenant's date and number formats.
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-hooks-use-docyrus-tenantpnpm add @docyrus/app-utils @docyrus/api-client @tanstack/react-queryThe module exports:
<DocyrusTenantProvider>: fetches/v1/tenant/preferences, normalizes the response and mounts<DateFormatProvider>and<NumberFormatProvider>for everything beneath it.useDocyrusTenant(): read-only hook returning{ preferences, dateUtils, numberUtils, isLoading }for ad-hoc formatting.normalizeTenantPreferences(envelope): pure helper that converts the API envelope into the shape the@docyrus/app-utilsfactories expect.
It needs an authenticated RestApiClient and a QueryClientProvider from @tanstack/react-query above the provider.
Requires @docyrus/app-utils >= 0.20.0 (ships a React Native build; no Metro config needed).
Why this exists
The @docyrus/app-utils factories (createDateUtils, createNumberUtils) read preferences keyed in snake_case (date_format, decimal_precision, …). The /v1/tenant/preferences API returns a { preferences: {...} } envelope with camelCase keys (dateFormat, decimalPrecision, …). Without normalization the factories silently fall back to their defaults. The provider unwraps the envelope, mirrors the keys, builds the utils and installs the contexts.
Usage
Mount the provider once near the root, below your auth and query providers:
import { useDocyrusAuth, useDocyrusClient } from '@docyrus/signin/react-native';
import { DocyrusTenantProvider } from '@/hooks/docyrus-native/use-docyrus-tenant';
export function TenantShell({ children }: { children: React.ReactNode }) {
const { status } = useDocyrusAuth();
const client = useDocyrusClient();
return (
<DocyrusTenantProvider client={client} enabled={status === 'authenticated'}>
{children}
</DocyrusTenantProvider>
);
}Every component that reads useDateFormat() or useNumberFormat() then uses the tenant's formats without per-screen wiring.
For ad-hoc formatting, read the utils directly:
import { Text } from 'react-native';
import { useDocyrusTenant } from '@/hooks/docyrus-native/use-docyrus-tenant';
export function ChartHeader({ date }: { date: string }) {
const { dateUtils, isLoading } = useDocyrusTenant();
if (isLoading || !dateUtils) return <Text>—</Text>;
return <Text>{dateUtils.formatDateLong(date)}</Text>;
}API Reference
<DocyrusTenantProvider>
| Prop | Type | Default | Description |
|---|---|---|---|
client | RestApiClient | null | undefined | — | API client used to fetch /v1/tenant/preferences. |
enabled | boolean | Boolean(client) | Defer the fetch until auth is ready. The fetch never runs without a client. |
userTimezone | string | device time zone | IANA time zone forwarded to createDateUtils. Native default is getDeviceTimeZone() (react-native-localize when installed, else Intl). Pass the user profile's time zone to override. |
staleTime | number | 1_800_000 (30 min) | TanStack Query stale window for the preferences query. |
children | ReactNode | — | Tree to wrap. |
The preferences query uses the key ['docyrus', 'tenant', 'preferences'].
useDocyrusTenant()
Takes no parameters. Returns: DocyrusTenantContextValue.
| Field | Type | Description |
|---|---|---|
preferences | TenantPreferences | null | Normalized preferences. null until loaded (or without a provider). |
dateUtils | DateUtils | null | createDateUtils({ preferences, userTimezone }). |
numberUtils | NumberUtils | null | createNumberUtils({ preferences }). |
isLoading | boolean | TanStack Query loading flag for the preferences fetch. |
Formatters installed by the provider
| Formatter | Behaviour |
|---|---|
formatDate | dateUtils.formatDate(value); raw string before preferences load or when formatting throws. |
formatDateTime | dateUtils.formatDateTime(value); same fallback. |
formatTime | toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' }). The preferences payload has no time format yet. |
formatNumber | numberUtils.formatNumber(value, { decimalPrecision?, thousandSeparator? }). 'percent' multiplies by 100 and appends %; 'currency' appends the currency code. Non-numeric input is returned as a string. |
normalizeTenantPreferences(envelope)
| Parameter | Type | Description |
|---|---|---|
envelope | unknown | The full { preferences, tenant, product, enums } envelope, or the inner preferences object. |
Returns: TenantPreferences | null. The input keys are kept, and date_format, date_time_format, long_date_format, thousand_separator, decimal_separator, decimal_precision and locale are filled from their camelCase counterparts. Returns null for non-object input.
import { createDateUtils, getTenantPreferences } from '@docyrus/app-utils';
import { normalizeTenantPreferences } from '@/hooks/docyrus-native/use-docyrus-tenant';
const preferences = normalizeTenantPreferences(await getTenantPreferences(client));
if (preferences) {
const dateUtils = createDateUtils({ preferences, userTimezone: 'Europe/Istanbul' });
}Type Exports
| Type | Description |
|---|---|
DocyrusTenantContextValue | Shape returned by useDocyrusTenant(). |
DocyrusTenantProviderProps | Props of <DocyrusTenantProvider>. |
useDocyrusPivotGrid
Pivot grid backed by a Docyrus data source. Aggregates on the device from raw records, or in the database through a pivot matrix and calculations, and returns a controller for the native PivotGrid components.
useDynamicFormView
Backend-agnostic form engine for React Native. Renders an IField schema with sections, tabs, collapsible panels, computed fields, field and form actions, validation tokens and a submit payload builder, with no network I/O.