Aaa / src /App.js
abeea's picture
Update src/App.js
f237710 verified
import React, { useState, useEffect } from 'react';
import { Heart, Lock, Unlock, Key, Send, Copy, Check, Calendar, User } from 'lucide-react';
const LoveMessageSystem = () => {
const [currentPartner, setCurrentPartner] = useState(null);
const [partnershipId, setPartnershipId] = useState(null);
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const [unlockKey, setUnlockKey] = useState('');
const [inputUnlockKey, setInputUnlockKey] = useState('');
const [showSetup, setShowSetup] = useState(true);
const [partnerName, setPartnerName] = useState('');
const [copied, setCopied] = useState(false);
const [notification, setNotification] = useState('');
// Initialize or load partnership
useEffect(() => {
const savedPartnerId = localStorage.getItem('partnerId');
const savedPartnershipId = localStorage.getItem('partnershipId');
if (savedPartnerId && savedPartnershipId) {
setCurrentPartner(parseInt(savedPartnerId));
setPartnershipId(savedPartnershipId);
setShowSetup(false);
loadMessages(savedPartnershipId);
loadUnlockKey(savedPartnershipId, parseInt(savedPartnerId));
}
}, []);
const generateId = () => {
return Math.random().toString(36).substr(2, 9);
};
const generateUnlockKey = () => {
return Math.random().toString(36).substr(2, 12).toUpperCase();
};
const createPartnership = async (partner) => {
const newPartnershipId = generateId();
const newUnlockKey = generateUnlockKey();
setCurrentPartner(partner);
setPartnershipId(newPartnershipId);
setUnlockKey(newUnlockKey);
localStorage.setItem('partnerId', partner.toString());
localStorage.setItem('partnershipId', newPartnershipId);
// Store in memory (simulating Supabase)
const partnership = {
id: newPartnershipId,
partner1_unlock_key: partner === 1 ? newUnlockKey : null,
partner2_unlock_key: partner === 2 ? newUnlockKey : null,
created_at: new Date().toISOString()
};
localStorage.setItem(`partnership_${newPartnershipId}`, JSON.stringify(partnership));
setShowSetup(false);
showNotification(`Welcome, Partner ${partner}! Share this ID with your partner: ${newPartnershipId}`);
};
const joinPartnership = async (existingId, partner) => {
const partnership = localStorage.getItem(`partnership_${existingId}`);
if (partnership) {
const newUnlockKey = generateUnlockKey();
const partnershipData = JSON.parse(partnership);
if (partner === 1) {
partnershipData.partner1_unlock_key = newUnlockKey;
} else {
partnershipData.partner2_unlock_key = newUnlockKey;
}
localStorage.setItem(`partnership_${existingId}`, JSON.stringify(partnershipData));
setCurrentPartner(partner);
setPartnershipId(existingId);
setUnlockKey(newUnlockKey);
localStorage.setItem('partnerId', partner.toString());
localStorage.setItem('partnershipId', existingId);
setShowSetup(false);
loadMessages(existingId);
showNotification(`Successfully joined partnership!`);
} else {
showNotification('Partnership ID not found!');
}
};
const loadMessages = (pId) => {
const stored = localStorage.getItem(`messages_${pId}`);
if (stored) {
setMessages(JSON.parse(stored));
}
};
const loadUnlockKey = (pId, partner) => {
const partnership = localStorage.getItem(`partnership_${pId}`);
if (partnership) {
const data = JSON.parse(partnership);
const key = partner === 1 ? data.partner1_unlock_key : data.partner2_unlock_key;
setUnlockKey(key || '');
}
};
const saveMessages = (pId, msgs) => {
localStorage.setItem(`messages_${pId}`, JSON.stringify(msgs));
};
const sendMessage = async () => {
if (!newMessage.trim()) return;
const message = {
id: generateId(),
partnership_id: partnershipId,
sender: currentPartner,
content: newMessage,
sent_at: new Date().toISOString(),
unlocked: false
};
const updatedMessages = [...messages, message];
setMessages(updatedMessages);
saveMessages(partnershipId, updatedMessages);
setNewMessage('');
showNotification('Message sent! 💕');
};
const checkAutoUnlock = (sentDate) => {
const sent = new Date(sentDate);
const now = new Date();
const daysDiff = Math.floor((now - sent) / (1000 * 60 * 60 * 24));
return daysDiff >= 30;
};
const useUnlockKey = () => {
if (!inputUnlockKey.trim()) {
showNotification('Please enter an unlock key');
return;
}
const partnership = localStorage.getItem(`partnership_${partnershipId}`);
if (!partnership) return;
const data = JSON.parse(partnership);
const otherPartnerKey = currentPartner === 1 ? data.partner2_unlock_key : data.partner1_unlock_key;
if (inputUnlockKey === otherPartnerKey) {
// Unlock all messages
const updatedMessages = messages.map(msg => ({
...msg,
unlocked: true
}));
setMessages(updatedMessages);
saveMessages(partnershipId, updatedMessages);
// Invalidate the used key and generate new one for other partner
if (currentPartner === 1) {
data.partner2_unlock_key = generateUnlockKey();
} else {
data.partner1_unlock_key = generateUnlockKey();
}
localStorage.setItem(`partnership_${partnershipId}`, JSON.stringify(data));
setInputUnlockKey('');
showNotification('Messages unlocked! 🎉');
} else {
showNotification('Invalid unlock key!');
}
};
const regenerateKey = () => {
const newKey = generateUnlockKey();
setUnlockKey(newKey);
const partnership = localStorage.getItem(`partnership_${partnershipId}`);
if (partnership) {
const data = JSON.parse(partnership);
if (currentPartner === 1) {
data.partner1_unlock_key = newKey;
} else {
data.partner2_unlock_key = newKey;
}
localStorage.setItem(`partnership_${partnershipId}`, JSON.stringify(data));
showNotification('New unlock key generated! 🔑');
}
};
const copyToClipboard = (text) => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const showNotification = (msg) => {
setNotification(msg);
setTimeout(() => setNotification(''), 3000);
};
const myMessages = messages.filter(m => m.sender === currentPartner);
const partnerMessages = messages.filter(m => m.sender !== currentPartner && m.sender !== null);
if (showSetup) {
return (
<div className="min-h-screen bg-gradient-to-br from-pink-100 via-purple-50 to-rose-100 p-8">
<div className="max-w-md mx-auto">
<div className="text-center mb-8">
<Heart className="w-16 h-16 text-rose-500 mx-auto mb-4" />
<h1 className="text-4xl font-bold text-rose-600 mb-2">Love Messages</h1>
<p className="text-gray-600">Connect with your partner</p>
</div>
<div className="bg-white rounded-2xl shadow-xl p-8 space-y-6">
<div>
<h2 className="text-2xl font-bold text-gray-800 mb-4">Create New Partnership</h2>
<div className="space-y-3">
<button
onClick={() => createPartnership(1)}
className="w-full bg-rose-500 text-white py-3 rounded-xl font-semibold hover:bg-rose-600 transition"
>
I'm Partner 1
</button>
<button
onClick={() => createPartnership(2)}
className="w-full bg-purple-500 text-white py-3 rounded-xl font-semibold hover:bg-purple-600 transition"
>
I'm Partner 2
</button>
</div>
</div>
<div className="border-t pt-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4">Join Existing</h2>
<input
type="text"
placeholder="Enter Partnership ID"
value={partnerName}
onChange={(e) => setPartnerName(e.target.value)}
className="w-full px-4 py-3 border border-gray-300 rounded-xl mb-3 focus:ring-2 focus:ring-rose-500 focus:border-transparent"
/>
<div className="space-y-3">
<button
onClick={() => joinPartnership(partnerName, 1)}
className="w-full bg-rose-400 text-white py-3 rounded-xl font-semibold hover:bg-rose-500 transition"
>
Join as Partner 1
</button>
<button
onClick={() => joinPartnership(partnerName, 2)}
className="w-full bg-purple-400 text-white py-3 rounded-xl font-semibold hover:bg-purple-500 transition"
>
Join as Partner 2
</button>
</div>
</div>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gradient-to-br from-pink-100 via-purple-50 to-rose-100 p-4 md:p-8">
{notification && (
<div className="fixed top-4 right-4 bg-white shadow-lg rounded-xl px-6 py-3 z-50 animate-pulse">
<p className="text-gray-800 font-semibold">{notification}</p>
</div>
)}
<div className="max-w-6xl mx-auto">
<div className="text-center mb-8">
<Heart className="w-12 h-12 text-rose-500 mx-auto mb-4" />
<h1 className="text-3xl md:text-4xl font-bold text-rose-600 mb-2">
Partner {currentPartner} Dashboard
</h1>
<p className="text-gray-600 text-sm">Partnership ID: {partnershipId}</p>
</div>
<div className="grid md:grid-cols-2 gap-6 mb-8">
{/* Send Message Section */}
<div className="bg-white rounded-2xl shadow-xl p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4 flex items-center gap-2">
<Send className="w-6 h-6 text-rose-500" />
Send Love Message
</h2>
<textarea
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
placeholder="Write your daily love message..."
className="w-full h-32 px-4 py-3 border border-gray-300 rounded-xl mb-4 focus:ring-2 focus:ring-rose-500 focus:border-transparent resize-none"
/>
<button
onClick={sendMessage}
className="w-full bg-rose-500 text-white py-3 rounded-xl font-semibold hover:bg-rose-600 transition flex items-center justify-center gap-2"
>
<Heart className="w-5 h-5" />
Send Message
</button>
</div>
{/* Unlock Key Section */}
<div className="bg-white rounded-2xl shadow-xl p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4 flex items-center gap-2">
<Key className="w-6 h-6 text-purple-500" />
Your Unlock Key
</h2>
<div className="bg-purple-50 rounded-xl p-4 mb-4">
<p className="text-sm text-gray-600 mb-2">Share this key with your partner:</p>
<div className="flex items-center gap-2">
<code className="flex-1 bg-white px-4 py-2 rounded-lg font-mono text-lg font-bold text-purple-600">
{unlockKey}
</code>
<button
onClick={() => copyToClipboard(unlockKey)}
className="bg-purple-500 text-white p-2 rounded-lg hover:bg-purple-600 transition"
>
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
</button>
</div>
</div>
<button
onClick={regenerateKey}
className="w-full bg-purple-500 text-white py-3 rounded-xl font-semibold hover:bg-purple-600 transition mb-4"
>
Generate New Key
</button>
<div className="border-t pt-4">
<p className="text-sm text-gray-600 mb-2">Use partner's key to unlock:</p>
<input
type="text"
value={inputUnlockKey}
onChange={(e) => setInputUnlockKey(e.target.value)}
placeholder="Enter unlock key"
className="w-full px-4 py-2 border border-gray-300 rounded-xl mb-2 focus:ring-2 focus:ring-purple-500 focus:border-transparent"
/>
<button
onClick={useUnlockKey}
className="w-full bg-green-500 text-white py-3 rounded-xl font-semibold hover:bg-green-600 transition flex items-center justify-center gap-2"
>
<Unlock className="w-5 h-5" />
Unlock Messages
</button>
</div>
</div>
</div>
{/* Messages Display */}
<div className="grid md:grid-cols-2 gap-6">
{/* My Messages */}
<div className="bg-white rounded-2xl shadow-xl p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4 flex items-center gap-2">
<User className="w-6 h-6 text-rose-500" />
My Messages ({myMessages.length})
</h2>
<div className="space-y-3 max-h-96 overflow-y-auto">
{myMessages.map((msg) => (
<div key={msg.id} className="bg-rose-50 rounded-xl p-4 border-2 border-rose-200">
<div className="flex items-center justify-between mb-2">
<span className="text-xs text-gray-500 flex items-center gap-1">
<Calendar className="w-3 h-3" />
{new Date(msg.sent_at).toLocaleDateString()}
</span>
</div>
<p className="text-gray-800">{msg.content}</p>
</div>
))}
{myMessages.length === 0 && (
<p className="text-gray-400 text-center py-8">No messages sent yet</p>
)}
</div>
</div>
{/* Partner's Messages */}
<div className="bg-white rounded-2xl shadow-xl p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4 flex items-center gap-2">
<Heart className="w-6 h-6 text-purple-500" />
Partner's Messages ({partnerMessages.length})
</h2>
<div className="space-y-3 max-h-96 overflow-y-auto">
{partnerMessages.map((msg) => {
const autoUnlock = checkAutoUnlock(msg.sent_at);
const isUnlocked = msg.unlocked || autoUnlock;
const daysRemaining = 30 - Math.floor((new Date() - new Date(msg.sent_at)) / (1000 * 60 * 60 * 24));
return (
<div
key={msg.id}
className={`rounded-xl p-4 border-2 ${
isUnlocked ? 'bg-green-50 border-green-200' : 'bg-gray-100 border-gray-300'
}`}
>
<div className="flex items-center justify-between mb-2">
<span className="text-xs text-gray-500 flex items-center gap-1">
<Calendar className="w-3 h-3" />
{new Date(msg.sent_at).toLocaleDateString()}
</span>
{isUnlocked ? (
<Unlock className="w-4 h-4 text-green-500" />
) : (
<Lock className="w-4 h-4 text-gray-500" />
)}
</div>
{isUnlocked ? (
<p className="text-gray-800">{msg.content}</p>
) : (
<div className="text-center py-4">
<Lock className="w-8 h-8 text-gray-400 mx-auto mb-2" />
<p className="text-gray-500 text-sm">
Unlocks in {daysRemaining} days
</p>
<p className="text-gray-400 text-xs mt-1">
Or use unlock key
</p>
</div>
)}
</div>
);
})}
{partnerMessages.length === 0 && (
<p className="text-gray-400 text-center py-8">
Waiting for partner's messages...
</p>
)}
</div>
</div>
</div>
</div>
</div>
);
};
export default LoveMessageSystem;