React
Functional component with hooks. Works in Vite, Next.js, Create React App, Remix, or anywhere React 18+ runs. No state library needed.
Install
The SDK isn't on npm yet. Save the module and its type declarations into your project — it's one dependency-free ES module, so there's nothing else to install.
curl -o src/lib/sensrik.js https://docs.sensrik.com/sensrik.js
curl -o src/lib/sensrik.d.ts https://docs.sensrik.com/sensrik.d.ts
A reusable Sensrik singleton
// src/lib/sensrik.ts
import { Sensrik } from './sensrik.js';
const STORAGE_KEY = 'sensrik.session';
function loadStored() {
try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null'); }
catch { return null; }
}
const stored = loadStored();
export const sensrik = new Sensrik({
accessToken: stored?.accessToken,
refreshToken: stored?.refreshToken,
onTokenRefreshed: (tokens) => localStorage.setItem(STORAGE_KEY, JSON.stringify(tokens)),
});
export function clearSession() {
localStorage.removeItem(STORAGE_KEY);
}
A login form
// src/components/LoginForm.tsx
import { useState } from 'react';
import { sensrik } from '../lib/sensrik';
export function LoginForm({ onSuccess }: { onSuccess: () => void }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState<string | null>(null);
const [busy, setBusy] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError(null);
setBusy(true);
try {
await sensrik.auth.login(email, password);
onSuccess();
} catch (err: any) {
setError(err?.status === 401 ? 'Invalid email or password.' : err?.message);
} finally {
setBusy(false);
}
}
return (
<form onSubmit={handleSubmit}>
{error && <div className="error">{error}</div>}
<input type="email" value={email} onChange={e => setEmail(e.target.value)} required />
<input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
<button type="submit" disabled={busy}>{busy ? 'Signing in…' : 'Sign in'}</button>
</form>
);
}
A devices list (auto-refreshes every 30s)
// src/components/DevicesList.tsx
import { useEffect, useState } from 'react';
import { sensrik } from '../lib/sensrik';
import type { Device } from '../lib/sensrik.js';
export function DevicesList() {
const [devices, setDevices] = useState<Device[]>([]);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
async function load() {
try {
const list = await sensrik.devices.list();
if (!cancelled) {
setDevices(list);
setError(null);
}
} catch (err: any) {
if (!cancelled) setError(err?.message ?? 'Failed to load');
} finally {
if (!cancelled) setLoading(false);
}
}
load();
const interval = setInterval(load, 30_000);
return () => { cancelled = true; clearInterval(interval); };
}, []);
if (loading) return <p>Loading…</p>;
if (error) return <p style={{ color: 'red' }}>{error}</p>;
if (devices.length === 0) return <p>No devices yet.</p>;
return (
<ul>
{devices.map(d => (
<li key={d.id}>
<strong>{d.name}</strong> — {d.isOnline ? '🟢 online' : '⚪ offline'} — {d.batterySoc ?? '—'}%
</li>
))}
</ul>
);
}
For a full storefront — login + devices + device detail with live charts — ask your Sensrik admin for the vanilla template and reimplement the pages in React. The SDK calls are the same.