Appearance
Hooks
useFetchApi
File: src/hooks/useFetchApi.ts
Low-level memoized fetch wrapper. Used internally by useQueryFetch and useMutationSubmit. You should rarely call this directly.
useQueryFetch
File: src/hooks/useQueryFetch.ts
React Query + fetchApi for GET requests.
ts
const { data, isLoading, isFetching, refetch } = useQueryFetch<MyType[]>({
queryKey: ['my-resource'],
url: '/my-resource',
params: { status: 'active' },
enabled: true,
});
// data is ApiResponse<MyType[]>
// data?.data is MyType[]useMutationSubmit
File: src/hooks/useMutationSubmit.ts
React Query + fetchApi for POST/PUT/PATCH/DELETE.
ts
const { mutate, isPending } = useMutationSubmit<ResponseType, BodyType>({
url: '/resource',
method: 'POST',
onSuccess: (res) => toast.success(res.message),
onError: (err) => toast.error(err.errorMessage),
});
mutate({ name: 'value' });useDataPagination
File: src/hooks/useDataPagination.ts
URL-synced paginated list with auto-generated filter helpers.
ts
const {
data, // ApiResource[]
pagination, // { page, count, limit, ... }
isLoading,
isFetching,
refetch,
// Auto-generated from generatedParamsKey:
searchQuery, // current search value
searchByQuery, // (value) => void — updates URL + fetches
regionQuery,
regionByQuery,
// Pagination
goToPage, // (page, perPage?) => void
setByQuery, // set multiple params at once
resetParams, // reset to defaultParams
isFiltered, // true if any param differs from default
} = useDataPagination({
dataSourceUrl: '/branches',
defaultParams: { page: 1, limit: 20 },
generatedParamsKey: {
search: ['search'],
region: ['region'],
},
});useI18n
File: src/hooks/useI18n.ts
ts
const { t, lang, setLang, isLoading } = useI18n();
t('nav.dashboard') // 'Dasbor' (id) | 'Dashboard' (en)
setLang('en') // persists to localStorage, updates i18nextuseToast
File: src/hooks/useToast.tsx
ts
const toast = useToast();
toast.success('Branch saved');
toast.error({ message: 'Save failed', title: 'Error', description: err.errorMessage });
toast.warning('Low occupancy detected');
toast.info('Data refreshed');Colors match Hermina status colors:
success→ sky blue (#0ea5e9)warning→ orange (#f97316)error→ red (#dc2626)info→ blue (#3b82f6)
Honeyframe Hooks
File: src/hooks/useHoneyframe.ts
React Query hooks for the Honeyframe Data API. Requires VITE_HF_BASE_URL and VITE_HF_TOKEN in .env.local. See docs/API.md → Honeyframe Data API for full API docs.
useWebappConfig
Fetches app config (pages, nav, filters). Cached indefinitely — only changes on republish.
ts
const { data: config, isLoading } = useWebappConfig('hermina360');
// config.pages — array of HFPage
// config.nav — nav items
// config.filters — global filter definitionsusePageBatch
Executes all card refs on a page in batch. Automatically groups by dashboard_id.
ts
const page = config?.pages.find(p => p.key === 'executive');
const { data: batchResult, isLoading } = usePageBatch(
'executive', // pageKey — used as React Query cache key
page?.card_refs, // blocks from config
{ branch_id: 5 }, // optional params / filters
);
// ALWAYS check error before reading rows
const cardData = batchResult?.['123']; // keyed by card_id as string
if (cardData?.error) { /* handle */ }
else { /* use cardData.rows, cardData.columns */ }staleTime: 5 minutes.
useBlockExecute
Executes a single code or html+data_sql block by index.
ts
const { data, isLoading } = useBlockExecute(
'hermina360', // appKey
'executive', // pageKey
0, // blockIdx
{ year: 2024 }, // filters
);
// data.rows, data.columns, data.errorstaleTime: 5 minutes.
useFilterOptions
Fetches dropdown options for a filter using its options_sql from config.
ts
const filterDef = config?.pages[0].filters['branch'];
const { data } = useFilterOptions(filterDef?.options_sql);
// data.options — HFFilterOption[] ({ value, label })
// data.error — check before renderingstaleTime: 10 minutes. Pass options_sql verbatim from config — do NOT modify.