Add floating QR code button on map for easy room joining
Tap the QR icon (bottom-right on mobile, top-right on desktop) to show an inline QR code overlay. Scan-to-join — tapping the QR dismisses it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0bea3ba73b
commit
8fd4ed22f9
|
|
@ -17,6 +17,7 @@ import ImportModal from '@/components/room/ImportModal';
|
||||||
import type { ImportedPlace } from '@/components/room/ImportModal';
|
import type { ImportedPlace } from '@/components/room/ImportModal';
|
||||||
import InstallBanner from '@/components/room/InstallBanner';
|
import InstallBanner from '@/components/room/InstallBanner';
|
||||||
import JoinForm from '@/components/room/JoinForm';
|
import JoinForm from '@/components/room/JoinForm';
|
||||||
|
import { QRCodeSVG } from 'qrcode.react';
|
||||||
import type { Participant, ParticipantLocation, LocationSource, Waypoint } from '@/types';
|
import type { Participant, ParticipantLocation, LocationSource, Waypoint } from '@/types';
|
||||||
|
|
||||||
// Dynamic import for map to avoid SSR issues with MapLibre
|
// Dynamic import for map to avoid SSR issues with MapLibre
|
||||||
|
|
@ -39,6 +40,7 @@ export default function RoomPage() {
|
||||||
const [showParticipants, setShowParticipants] = useState(true);
|
const [showParticipants, setShowParticipants] = useState(true);
|
||||||
const [showMeetingPoint, setShowMeetingPoint] = useState(false);
|
const [showMeetingPoint, setShowMeetingPoint] = useState(false);
|
||||||
const [showImport, setShowImport] = useState(false);
|
const [showImport, setShowImport] = useState(false);
|
||||||
|
const [showQR, setShowQR] = useState(false);
|
||||||
const [currentUser, setCurrentUser] = useState<{ name: string; emoji: string } | null>(null);
|
const [currentUser, setCurrentUser] = useState<{ name: string; emoji: string } | null>(null);
|
||||||
const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null);
|
const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null);
|
||||||
const [selectedWaypoint, setSelectedWaypoint] = useState<Waypoint | null>(null);
|
const [selectedWaypoint, setSelectedWaypoint] = useState<Waypoint | null>(null);
|
||||||
|
|
@ -428,6 +430,41 @@ export default function RoomPage() {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Floating QR button */}
|
||||||
|
<button
|
||||||
|
onClick={() => setShowQR(!showQR)}
|
||||||
|
className="absolute bottom-6 right-4 md:top-4 md:bottom-auto flex items-center gap-2 px-3 py-2.5 rounded-full bg-rmaps-dark/90 backdrop-blur border border-white/20 hover:bg-rmaps-dark hover:border-white/30 transition-colors shadow-lg z-20"
|
||||||
|
title="Show room QR code"
|
||||||
|
>
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<rect x="3" y="3" width="7" height="7" />
|
||||||
|
<rect x="14" y="3" width="7" height="7" />
|
||||||
|
<rect x="3" y="14" width="7" height="7" />
|
||||||
|
<rect x="14" y="14" width="3" height="3" />
|
||||||
|
<line x1="21" y1="14" x2="21" y2="14.01" />
|
||||||
|
<line x1="21" y1="21" x2="21" y2="21.01" />
|
||||||
|
<line x1="17" y1="17" x2="17" y2="21" />
|
||||||
|
<line x1="21" y1="17" x2="21" y2="17.01" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* QR code overlay */}
|
||||||
|
{showQR && (
|
||||||
|
<div
|
||||||
|
className="absolute bottom-20 right-4 md:top-16 md:bottom-auto z-30 bg-white rounded-2xl p-4 shadow-2xl"
|
||||||
|
onClick={() => setShowQR(false)}
|
||||||
|
>
|
||||||
|
<QRCodeSVG
|
||||||
|
value={typeof window !== 'undefined' ? `${window.location.origin}/${slug}` : `https://rmaps.online/${slug}`}
|
||||||
|
size={160}
|
||||||
|
bgColor="#ffffff"
|
||||||
|
fgColor="#0f172a"
|
||||||
|
level="M"
|
||||||
|
/>
|
||||||
|
<p className="text-center text-xs text-slate-500 mt-2 font-medium">Scan to join</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Connection status indicator */}
|
{/* Connection status indicator */}
|
||||||
{!isConnected && (
|
{!isConnected && (
|
||||||
<div className="absolute top-4 left-1/2 -translate-x-1/2 bg-yellow-500/90 text-black text-sm px-3 py-1.5 rounded-full z-30">
|
<div className="absolute top-4 left-1/2 -translate-x-1/2 bg-yellow-500/90 text-black text-sm px-3 py-1.5 rounded-full z-30">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue