import { useState, useEffect } from 'react';
import { ChevronRight, Logs, MessageSquare, Send, Settings, X } from 'lucide-react';
import { toast } from '../ui/sonner';
import { usePush } from '../../contexts/PushSubscriptionContext';
import type { Channel, Contact } from '../../types';
import { getContactDisplayName } from '../../utils/pubkey';
import { Button } from '../ui/button';
import { Checkbox } from '../ui/checkbox';
import { Input } from '../ui/input';
import { Label } from '../ui/label';
import { Separator } from '../ui/separator';
import { cn } from '../../lib/utils';
import { ContactAvatar } from '../ContactAvatar';
import {
captureLastViewedConversationFromHash,
getReopenLastConversationEnabled,
setReopenLastConversationEnabled,
} from '../../utils/lastViewedConversation';
import { ThemeSelector } from './ThemeSelector';
import { getLocalLabel, setLocalLabel, type LocalLabel } from '../../utils/localLabel';
import {
DISTANCE_UNIT_LABELS,
DISTANCE_UNITS,
setSavedDistanceUnit,
} from '../../utils/distanceUnits';
import { useDistanceUnit } from '../../contexts/DistanceUnitContext';
import {
DEFAULT_FONT_SCALE,
FONT_SCALE_SLIDER_STEP,
MAX_FONT_SCALE,
MIN_FONT_SCALE,
getSavedFontScale,
setSavedFontScale,
} from '../../utils/fontScale';
import { getAutoFocusInputEnabled, setAutoFocusInputEnabled } from '../../utils/autoFocusInput';
import {
getTextReplaceEnabled,
setTextReplaceEnabled as saveTextReplaceEnabled,
getTextReplaceMapJson,
setTextReplaceMapJson,
DEFAULT_MAP_JSON,
} from '../../utils/textReplace';
import {
BATTERY_DISPLAY_CHANGE_EVENT,
getShowBatteryPercent,
setShowBatteryPercent as saveBatteryPercent,
getShowBatteryVoltage,
setShowBatteryVoltage as saveBatteryVoltage,
} from '../../utils/batteryDisplay';
import {
STATUS_DOT_PULSE_CHANGE_EVENT,
getStatusDotPulseEnabled,
setStatusDotPulseEnabled as saveStatusDotPulse,
} from '../../utils/statusDotPulse';
/** Resolve a state key like "contact-abc123" or "channel-def456" to a display name. */
function resolveConversationName(
stateKey: string,
contacts: Contact[],
channels: Channel[]
): string {
if (stateKey.startsWith('contact-')) {
const pubkey = stateKey.slice('contact-'.length);
const contact = contacts.find((c) => c.public_key === pubkey);
return contact ? getContactDisplayName(contact.name, contact.public_key) : pubkey.slice(0, 12);
}
if (stateKey.startsWith('channel-')) {
const key = stateKey.slice('channel-'.length);
const channel = channels.find((c) => c.key === key);
if (channel?.name) return channel.name.startsWith('#') ? channel.name : `#${channel.name}`;
return `#${key.slice(0, 12)}`;
}
return stateKey;
}
function PushDeviceManagement({
contacts = [],
channels = [],
}: {
contacts?: Contact[];
channels?: Channel[];
}) {
const {
isSupported,
allSubscriptions,
pushConversations,
loading,
subscribe,
currentSubscriptionId,
toggleConversation,
deleteSubscription,
testPush,
refreshSubscriptions,
} = usePush();
useEffect(() => {
refreshSubscriptions();
}, [refreshSubscriptions]);
if (!isSupported) {
return (
Web Push Notifications
{window.isSecureContext
? 'Push notifications are not supported by this browser.'
: 'Web Push requires HTTPS. Access RemoteTerm over HTTPS (self-signed certificates work) to enable push notifications.'}
);
}
return (
Web Push Notifications
Receive notifications even when the browser is closed. Use the bell icon in any
conversation header to enable push for that contact or channel, or subscribe this browser
to receive notifications for all push-enabled conversations.
The set of channels or DMs that trigger push notifications are global per-install (i.e.
all devices that register for Web Push will have the same set of channels/DMs that trigger
notifications). Subscribing or unsubscribing a particular browser only controls whether
that browser receives notifications for the configured set of channels/DMs.