[feat](client): scan an instance-relative join payload
The service mints /api/alarm/a/{alertId}#{token} with no host, so the QR renders against the configured instance and keeps working when the instance moves or is reached by another name. The scanner now matches path shape and fragment and never the host, so legacy alarm.dcntrlized.org codes and other instances codes still join; error copy distinguishes a malformed code from a wrong-alert token.
This commit is contained in:
@@ -20,6 +20,9 @@ import { ScanLine, X } from 'lucide-react-native';
|
||||
import { AppText, Button, ErrorBanner, Field, Header, TextInputBox } from '../components/ui';
|
||||
import { useAlarm } from '../state/AlarmContext';
|
||||
import { joinErrorMessage } from '../services/alarmApi';
|
||||
import { buildDeviceLabel } from '../lib/deviceLabel';
|
||||
import { canDeliverRealAlarm } from '../lib/takeoverReadiness';
|
||||
import { useAlarmPermissions } from '../state/useAlarmPermissions';
|
||||
import { parseQrPayload, parseManualToken, qrErrorMessage } from '../lib/qrPayload';
|
||||
import { openAppSettings } from '../services/alarmNative';
|
||||
import type { RootStackParamList } from '../navigation';
|
||||
@@ -64,7 +67,7 @@ type Rt = RouteProp<RootStackParamList, 'Scanner'>;
|
||||
export default function ScannerScreen() {
|
||||
const navigation = useNavigation<Nav>();
|
||||
const { params } = useRoute<Rt>();
|
||||
const { joinAlert, deviceId } = useAlarm();
|
||||
const { joinAlert } = useAlarm();
|
||||
const { hasPermission, requestPermission, canRequestPermission } = useCameraPermission();
|
||||
const device = useCameraDevice('back');
|
||||
|
||||
@@ -117,10 +120,19 @@ export default function ScannerScreen() {
|
||||
}, [reduceMotion, sweepValue]);
|
||||
|
||||
const targetAlertId = params?.alertId;
|
||||
const { perms } = useAlarmPermissions();
|
||||
|
||||
const complete = useCallback(
|
||||
async (alertId: string, token: string) => {
|
||||
if (busy || handled.current) return;
|
||||
// Subscribing on a device that cannot fire a real alarm would present as
|
||||
// armed while being unable to ring. Block it and name the fix.
|
||||
if (perms && !canDeliverRealAlarm(perms)) {
|
||||
setError(
|
||||
'This device cannot deliver a real alarm yet. Allow exact alarms and the full-screen takeover in Settings, then scan again.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
handled.current = true;
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
@@ -128,7 +140,8 @@ export default function ScannerScreen() {
|
||||
const record = await joinAlert({
|
||||
alertId,
|
||||
subscribeToken: token,
|
||||
deviceLabel: `Android ${deviceId?.slice(-4) ?? ''}`.trim(),
|
||||
// Device *role*, never a slice of the identity token.
|
||||
deviceLabel: buildDeviceLabel(),
|
||||
});
|
||||
setJoinedName(record.name || alertId);
|
||||
// Give the confirmation a beat, then return to the detail screen.
|
||||
@@ -142,7 +155,7 @@ export default function ScannerScreen() {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[busy, deviceId, joinAlert, navigation],
|
||||
[busy, joinAlert, navigation, perms],
|
||||
);
|
||||
|
||||
const onScanned = useCallback(
|
||||
@@ -287,7 +300,7 @@ export default function ScannerScreen() {
|
||||
onChangeText={setManual}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
placeholder="https://alarm.dcntrlized.org/a/…#token"
|
||||
placeholder="/api/alarm/a/…#token or https://your-instance/…"
|
||||
accessibilityLabel="Alert code or link"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
Reference in New Issue
Block a user