A standalone server-side rendered React Router application for displaying real-time token information from the Care API.
- Server-Side Rendering: Fast initial page loads with React Router SSR
- Real-Time Updates: Auto-refresh token data at configurable intervals
- Authentication: Secure server-side authentication with Care API
- Responsive Grid Layout: Automatically adjusts layout based on number of service points
- Fullscreen Display: Optimized for kiosk/display mode with mobile-friendly meta tags
pnpm installCreate a .env file in the project root:
CARE_API_URL=https://your-care-api.example.com
CARE_USERNAME=token_display_user
CARE_PASSWORD=secure_password
TOKEN_REFRESH_INTERVAL=10000
CONFIG_REFRESH_INTERVAL=300000
JWT_TOKEN_REFRESH_INTERVAL=300000
# Display Configurations (JSON array - must be on a single line)
DISPLAYS_CONFIG='[{"name":"OPD Counter 1","facilityId":"abc-123-facility-id","resources":"p:user-uuid-1,l:location-uuid-1","description":"Main OPD counter for general consultations"},{"name":"Emergency Department","facilityId":"abc-123-facility-id","resources":"h:service-uuid-1","description":"Emergency department token display"}]'Environment Variables:
CARE_API_URL: Base URL of the Care API (required)CARE_USERNAME: Username for API authentication (required)CARE_PASSWORD: Password for API authentication (required)TOKEN_REFRESH_INTERVAL: Token refresh interval in milliseconds (default: 10000 = 10 seconds)CONFIG_REFRESH_INTERVAL: Configuration refresh interval in milliseconds (default: 300000 = 5 minutes)JWT_TOKEN_REFRESH_INTERVAL: JWT token refresh interval in milliseconds (default: 300000 = 5 minutes)DISPLAYS_CONFIG: JSON array of display configurations (optional). Each display should have:name: Display name shown on the home pagefacilityId: UUID of the facilityresources: Comma-separated list of resources (format:type:id)description(optional): Description shown on the display card
pnpm devThe application will be available at http://localhost:5173
pnpm build
pnpm startWhen you start the application, navigate to http://localhost:5173 to see the home page. If you have configured displays using the DISPLAYS_CONFIG environment variable, you'll see cards for each display that you can click to navigate to the corresponding token display.
Navigate to the display route with the following URL pattern:
/display/{facilityId}?resources={resourceType}:{resourceId},{resourceType}:{resourceId},...
Parameters:
facilityId: The UUID of the facilityresources: Comma-separated list of resources in the formattype:id
Resource Types:
p: Healthcare practitioner/userl: Physical location within the facilityh: Healthcare service
Example:
http://localhost:5173/display/abc-123-facility-id?resources=p:user-uuid,l:location-uuid,h:service-uuid
This will display token information for all active sub-queues associated with the specified resources.
- Server middleware authenticates with Care API on first request
- JWT tokens are cached in memory with automatic refresh
- All API requests use the authenticated token
- Token automatically refreshes 5 minutes before expiration
- Route loader fetches data server-side on initial load
- Client-side revalidation refreshes data at configured intervals
- Service points display current IN_PROGRESS tokens
- Grid layout automatically adjusts based on number of service points
token_display/
├── app/
│ ├── components/
│ │ ├── ServicePointCard.tsx # Individual service point display
│ │ └── TokenDisplay.tsx # Main grid layout component
│ ├── lib/
│ │ ├── api.ts # API client utilities
│ │ ├── auth.server.ts # Server-side authentication
│ │ └── utils.ts # Utility functions
│ ├── routes/
│ │ ├── display.$facilityId.tsx # Token display route
│ │ └── home.tsx # Home/info page
│ ├── styles/
│ │ └── token-display.css # Custom animations
│ ├── types/
│ │ ├── api.ts # API type definitions
│ │ ├── schedule.ts # Resource type definitions
│ │ ├── tokenQueue.ts # Token queue types
│ │ ├── tokens.ts # Token types
│ │ └── tokenSubQueue.ts # Sub-queue types
│ ├── config.ts # Configuration loader
│ ├── root.tsx # Root layout
│ └── routes.ts # Route configuration
├── package.json
└── README.md
The application uses Tailwind CSS for styling. Colors and layout can be customized in:
app/components/TokenDisplay.tsx- Grid layout and background colorsapp/components/ServicePointCard.tsx- Card styling and token displayapp/styles/token-display.css- Custom animations
Adjust refresh intervals via environment variables:
TOKEN_REFRESH_INTERVAL: How often to refresh token dataCONFIG_REFRESH_INTERVAL: How often to refresh configuration (not currently used, reserved for future)
The grid automatically adjusts based on the number of service points:
- 1 service point: Full screen (1 column)
- 2-4 service points: 2 columns
- 5+ service points: 6 columns (responsive 3-column layout)
If you see authentication errors:
- Verify
CARE_API_URLis correct and accessible - Check
CARE_USERNAMEandCARE_PASSWORDare valid - Ensure the user account has appropriate permissions
- Check server logs for detailed error messages
If no service points are displayed:
- Verify the facility ID is correct
- Check that resources exist and are properly formatted
- Ensure sub-queues are in ACTIVE status
- Verify a primary queue exists for the date
If tokens don't update:
- Check browser console for errors
- Verify
TOKEN_REFRESH_INTERVALis set correctly - Ensure tokens are being updated to IN_PROGRESS status in Care
- Check network tab for failed API requests
If displays don't appear on the home page:
- Ensure the JSON is on a single line -
.envfiles don't support multi-line values - Verify the JSON is valid using a JSON validator
- Use single quotes around the entire JSON string
- Use double quotes for JSON property names and values
- Check server logs for parsing errors
Correct format:
DISPLAYS_CONFIG='[{"name":"Display 1","facilityId":"uuid","resources":"p:uuid"}]'Incorrect format (will fail):
DISPLAYS_CONFIG='[
{"name":"Display 1","facilityId":"uuid","resources":"p:uuid"}
]'npm run typechecknpm run buildThis project is part of the Care ecosystem.