ManuallyRequestSheet
The ManuallyRequestSheet module provides compound React components for creating customizable bottom sheet modals for manual health data authorization requests. Built on @gorhom/bottom-sheet with themed styling and platform-specific imagery.
Overview
The ManuallyRequestSheet module is built using a compound component pattern, providing maximum flexibility for different authorization flows while maintaining visual consistency across your healthcare application.
Key Features
- Bottom Sheet Modal: Built on
@gorhom/bottom-sheetfor native-like experience - Compound Components: Flexible sub-components for custom layouts
- Platform Support: Built-in imagery for Apple, Google, and Fitbit
- Theme Integration: Automatically adapts to app theme colors and spacing
- Safe Area Handling: Proper safe area insets for all device types
- Dynamic Sizing: Automatically adjusts height based on content
- Accessibility: Full accessibility support with proper labeling
- TypeScript: Full type safety throughout all components
Basic Example
import { ObservationCode } from "@ovok/core";
import { AppleHealthSyncProps, DataSync } from "@ovok/native";
import { BottomSheetModal } from "@gorhom/bottom-sheet";
import { HKQuantityTypeIdentifier } from "@kingstinct/react-native-healthkit";
import React from "react";
const dataToSync: AppleHealthSyncProps["dataToSync"] = {
"body-temperature": {
typeIdentifiers: [
{
typeIdentifier: HKQuantityTypeIdentifier.bodyTemperature,
code: ObservationCode.BODY_TEMPERATURE,
},
],
minDate: new Date("2025-01-01"),
},
};
const HealthDataSync = () => {
const [skipRequest, setSkipRequest] = React.useState(false);
const manuallyRequestSheetRef = React.useRef<BottomSheetModal | null>(null);
const shouldOpenManuallyRequestSheet = React.useRef(true);
const onRefManuallyRequestSheet = React.useCallback(
(ref: BottomSheetModal | null) => {
// This is a workaround to ensure the sheet is expanded when the ref is set (after the component is mounted)
// if you need to open sheet on button press, you can use the `shouldOpenManuallyRequestSheet` ref and remove the `if` check
manuallyRequestSheetRef.current = ref;
if (shouldOpenManuallyRequestSheet.current) {
ref?.present();
shouldOpenManuallyRequestSheet.current = false;
}
},
[],
);
const handleSkip = React.useCallback(() => {
// in this case, we want to show skipped state in screen
// but you can also navigate user to another screen
setSkipRequest(true);
manuallyRequestSheetRef.current?.dismiss();
}, []);
const renderManualRequestUI = React.useCallback(
(requestAccess: () => void) => {
return (
<DataSync.ManuallyRequestSheet ref={onRefManuallyRequestSheet}>
<DataSync.ManuallyRequestSheet.Container>
<DataSync.ManuallyRequestSheet.Title>
Manually Request
</DataSync.ManuallyRequestSheet.Title>
<DataSync.ManuallyRequestSheet.Description>
Sync your weight, steps, and other data to track your progress
effortlessly.
</DataSync.ManuallyRequestSheet.Description>
<DataSync.ManuallyRequestSheet.Image for="apple" />
<DataSync.ManuallyRequestSheet.RequestButton
onPress={requestAccess}
>
Request
</DataSync.ManuallyRequestSheet.RequestButton>
<DataSync.ManuallyRequestSheet.SkipButton onPress={handleSkip}>
Skip
</DataSync.ManuallyRequestSheet.SkipButton>
</DataSync.ManuallyRequestSheet.Container>
</DataSync.ManuallyRequestSheet>
);
},
[onRefManuallyRequestSheet, handleSkip],
);
return (
// This component is wrapped in the AppleHealthAuthorizationProvider
// to handle the authorization process
<DataSync.AppleHealthAuthorizationProvider
readIdentifiers={[HKQuantityTypeIdentifier.bodyMass]}
renderManualRequestUI={renderManualRequestUI}
skipRequest={skipRequest}
>
{/* You have to be authorized to sync the health data */}
<DataSync.AppleHealthSync dataToSync={dataToSync} />
</DataSync.AppleHealthAuthorizationProvider>
);
};
export default HealthDataSync;
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | React.ReactNode | ✓ | - | Content to render in the bottom sheet |
backgroundStyle | ViewStyle | - | - | Custom background styling (merged with theme) |
enableDynamicSizing | boolean | - | true | Automatically adjust height based on content |
enablePanDownToClose | boolean | - | false | Allow closing by panning down |
Inherits all BottomSheetModalProps from @gorhom/bottom-sheet
Component Behavior
The ManuallyRequestSheet component provides a modal container that:
- Modal Presentation: Overlays content above the current screen
- Dynamic Height: Automatically adjusts to fit content when
enableDynamicSizingis true - Theme Integration: Uses app theme colors for background and styling
- Safe Area Handling: Respects device safe areas for proper layout
- Gesture Control: Optional pan-down-to-close gesture support
Background Styling
The component automatically applies theme-based background styling:
// Default background style (merged with custom backgroundStyle)
{
backgroundColor: theme.colors.background,
borderTopLeftRadius: theme.borderRadius(5),
borderTopRightRadius: theme.borderRadius(5),
}
Ref API
The component forwards ref to the underlying BottomSheetModal, providing access to:
Methods
present()- Opens the bottom sheetdismiss()- Closes the bottom sheetexpand()- Expands to full heightcollapse()- Collapses to snap pointclose()- Alias for dismiss()
Styling
Theme Colors Used
theme.colors.background- Modal background colortheme.borderRadius(5)- Top corner radius for modal appearance
Components
- ManuallyRequestSheet.Container - Main content container with padding and spacing
- ManuallyRequestSheet.Title - Styled title text component for authorization prompts
- ManuallyRequestSheet.Description - Body text for authorization description
- ManuallyRequestSheet.Image - Platform-specific imagery container with built-in providers
- ManuallyRequestSheet.RequestButton - Primary action button (contained style)
- ManuallyRequestSheet.SkipButton - Secondary action button (text style)
Common Patterns
Authorization Flow States
The ManuallyRequestSheet component supports several common authorization flow states:
- Introduction: Shows platform information and benefits
- Permission Selection: Optional step for granular permission control
- Authorization Request: Primary action to grant permissions
- Error Handling: Graceful handling of permission denials
- Success/Completion: Post-authorization feedback
Platform Support
The component supports various health platforms:
- Apple Health (
for="apple") - Google Health Connect (
for="google") - Custom providers (with custom imagery)