feat: Auto-load saved user and remember last visited room
- JoinForm now pre-populates name/emoji from localStorage and shows a "Quick Join as [name]" button for returning users - Home page shows "Rejoin /[room]" button when user has visited before - Room slug saved to localStorage on every visit for quick rejoin 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
47dea7c9c3
commit
2284f94ee3
|
|
@ -46,6 +46,8 @@ export default function RoomPage() {
|
||||||
const stored = localStorage.getItem('rmaps_user');
|
const stored = localStorage.getItem('rmaps_user');
|
||||||
if (stored) {
|
if (stored) {
|
||||||
setCurrentUser(JSON.parse(stored));
|
setCurrentUser(JSON.parse(stored));
|
||||||
|
// Save this as the last visited room
|
||||||
|
localStorage.setItem('rmaps_last_room', slug);
|
||||||
// Check if user had location sharing enabled for this room
|
// Check if user had location sharing enabled for this room
|
||||||
const sharingPref = localStorage.getItem(`rmaps_sharing_${slug}`);
|
const sharingPref = localStorage.getItem(`rmaps_sharing_${slug}`);
|
||||||
if (sharingPref === 'true') {
|
if (sharingPref === 'true') {
|
||||||
|
|
@ -61,6 +63,7 @@ export default function RoomPage() {
|
||||||
const handleJoin = (name: string, emoji: string) => {
|
const handleJoin = (name: string, emoji: string) => {
|
||||||
const user = { name, emoji };
|
const user = { name, emoji };
|
||||||
localStorage.setItem('rmaps_user', JSON.stringify(user));
|
localStorage.setItem('rmaps_user', JSON.stringify(user));
|
||||||
|
localStorage.setItem('rmaps_last_room', slug);
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
setNeedsJoin(false);
|
setNeedsJoin(false);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ export default function HomePage() {
|
||||||
const [emoji, setEmoji] = useState('');
|
const [emoji, setEmoji] = useState('');
|
||||||
const [roomName, setRoomName] = useState('');
|
const [roomName, setRoomName] = useState('');
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
const [lastRoom, setLastRoom] = useState<string | null>(null);
|
||||||
|
|
||||||
// Load saved user info from localStorage on mount
|
// Load saved user info from localStorage on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -34,6 +35,11 @@ export default function HomePage() {
|
||||||
loadedEmoji = user.emoji;
|
loadedEmoji = user.emoji;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Load last visited room
|
||||||
|
const lastVisited = localStorage.getItem('rmaps_last_room');
|
||||||
|
if (lastVisited) {
|
||||||
|
setLastRoom(lastVisited);
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore parse errors
|
// Ignore parse errors
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +59,7 @@ export default function HomePage() {
|
||||||
|
|
||||||
// Store user info in localStorage for the session
|
// Store user info in localStorage for the session
|
||||||
localStorage.setItem('rmaps_user', JSON.stringify({ name, emoji }));
|
localStorage.setItem('rmaps_user', JSON.stringify({ name, emoji }));
|
||||||
|
localStorage.setItem('rmaps_last_room', slug);
|
||||||
|
|
||||||
// Navigate to the room (will create it if it doesn't exist)
|
// Navigate to the room (will create it if it doesn't exist)
|
||||||
router.push(`/${slug}`);
|
router.push(`/${slug}`);
|
||||||
|
|
@ -65,9 +72,16 @@ export default function HomePage() {
|
||||||
|
|
||||||
// Clean the slug
|
// Clean the slug
|
||||||
const cleanSlug = joinSlug.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
const cleanSlug = joinSlug.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
||||||
|
localStorage.setItem('rmaps_last_room', cleanSlug);
|
||||||
router.push(`/${cleanSlug}`);
|
router.push(`/${cleanSlug}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejoinLastRoom = () => {
|
||||||
|
if (!name.trim() || !lastRoom) return;
|
||||||
|
localStorage.setItem('rmaps_user', JSON.stringify({ name, emoji }));
|
||||||
|
router.push(`/${lastRoom}`);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen flex flex-col items-center justify-center p-4">
|
<main className="min-h-screen flex flex-col items-center justify-center p-4">
|
||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
|
|
@ -79,6 +93,23 @@ export default function HomePage() {
|
||||||
<p className="text-white/60">Find your friends at events</p>
|
<p className="text-white/60">Find your friends at events</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Quick Rejoin Card - show when user has saved info and last room */}
|
||||||
|
{isLoaded && name && lastRoom && (
|
||||||
|
<div className="room-panel rounded-2xl p-6">
|
||||||
|
<p className="text-white/60 text-sm text-center mb-4">Welcome back, {name}!</p>
|
||||||
|
<button
|
||||||
|
onClick={handleRejoinLastRoom}
|
||||||
|
className="btn-primary w-full text-lg py-3 flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<span className="text-xl">{emoji}</span>
|
||||||
|
<span>Rejoin /{lastRoom}</span>
|
||||||
|
</button>
|
||||||
|
<p className="text-white/40 text-xs text-center mt-3">
|
||||||
|
Or create/join a different room below
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Main Card */}
|
{/* Main Card */}
|
||||||
<div className="room-panel rounded-2xl p-6 space-y-6">
|
<div className="room-panel rounded-2xl p-6 space-y-6">
|
||||||
{/* User Setup */}
|
{/* User Setup */}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
const EMOJIS = ['😀', '😎', '🤓', '🥳', '🦊', '🐱', '🐶', '🦄', '🌟', '🔥', '💜', '🎮'];
|
const EMOJIS = ['😀', '😎', '🤓', '🥳', '🦊', '🐱', '🐶', '🦄', '🌟', '🔥', '💜', '🎮'];
|
||||||
|
|
||||||
|
|
@ -11,7 +11,31 @@ interface JoinFormProps {
|
||||||
|
|
||||||
export default function JoinForm({ roomSlug, onJoin }: JoinFormProps) {
|
export default function JoinForm({ roomSlug, onJoin }: JoinFormProps) {
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
const [emoji, setEmoji] = useState(EMOJIS[Math.floor(Math.random() * EMOJIS.length)]);
|
const [emoji, setEmoji] = useState('');
|
||||||
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
|
// Load saved user info from localStorage
|
||||||
|
useEffect(() => {
|
||||||
|
let loadedEmoji = '';
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('rmaps_user');
|
||||||
|
if (stored) {
|
||||||
|
const user = JSON.parse(stored);
|
||||||
|
if (user.name) setName(user.name);
|
||||||
|
if (user.emoji) {
|
||||||
|
setEmoji(user.emoji);
|
||||||
|
loadedEmoji = user.emoji;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore parse errors
|
||||||
|
}
|
||||||
|
// Set random emoji if none loaded
|
||||||
|
if (!loadedEmoji) {
|
||||||
|
setEmoji(EMOJIS[Math.floor(Math.random() * EMOJIS.length)]);
|
||||||
|
}
|
||||||
|
setIsLoaded(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -30,6 +54,24 @@ export default function JoinForm({ roomSlug, onJoin }: JoinFormProps) {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Quick join option if user already has saved info */}
|
||||||
|
{isLoaded && name && (
|
||||||
|
<div className="mb-6 p-4 bg-rmaps-primary/10 border border-rmaps-primary/30 rounded-lg">
|
||||||
|
<p className="text-white/60 text-sm mb-3 text-center">Welcome back!</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => onJoin(name.trim(), emoji)}
|
||||||
|
className="w-full btn-primary py-3 flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<span className="text-xl">{emoji}</span>
|
||||||
|
<span>Join as {name}</span>
|
||||||
|
</button>
|
||||||
|
<p className="text-white/40 text-xs text-center mt-2">
|
||||||
|
Or customize below
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
{/* Emoji picker */}
|
{/* Emoji picker */}
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue