// DEPLOY_CONFIG: {"triggers": [{"name": "remind_review_card_if_stale", "on": "collection.update", "collection": "cards", "actions": [{"type": "email", "to": "{{owner_email}}", "subject": "Reminder to review your card", "body": "This is a reminder to review your card because it has not been updated in 6 months."}]}]}
import { useEffect, useMemo, useState } from 'react';
import { useAuth } from '@deplixo/sdk';
import { useCollection } from '@deplixo/sdk';
import { MedicalInfo } from './components/MedicalInfo.jsx';
import { EmergencyContacts } from './components/EmergencyContacts.jsx';
import { InsuranceInfo } from './components/InsuranceInfo.jsx';
import { CardView } from './components/CardView.jsx';
function App() {
const { user, loading: authLoading, login, logout } = useAuth();
const { items: ownerCards, loading: cardLoading, add, update } = useCollection('emergency-card', { personal: true });
const { items: shareAccessItems, loading: shareLoading, add: addShareAccess, update: updateShareAccess, remove: removeShareAccess } = useCollection('emergency-card-share', { personal: true });
const [activeTab, setActiveTab] = useState('card');
const [shareName, setShareName] = useState('');
const [shareEmail, setShareEmail] = useState('');
const [shareRole, setShareRole] = useState('viewer');
const [shareNote, setShareNote] = useState('');
const [shareMessage, setShareMessage] = useState('');
const [shareError, setShareError] = useState('');
const tabs = [
{ id: 'card', label: '🪪 Card', icon: '🪪' },
{ id: 'medical', label: '🩺 Medical', icon: '🩺' },
{ id: 'contacts', label: '📞 Contacts', icon: '📞' },
{ id: 'insurance', label: '🏥 Insurance', icon: '🏥' },
];
const ownerCard = useMemo(() => {
if (!user) return null;
return ownerCards?.find(card => card.ownerId === user.id) || null;
}, [ownerCards, user]);
const sharedAccess = useMemo(() => {
if (!user) return [];
return (shareAccessItems || [])
.filter(item => item.ownerId === user.id)
.sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
}, [shareAccessItems, user]);
useEffect(() => {
if (user && activeTab === 'card' && !ownerCard && !cardLoading) {
const seedCard = {
ownerId: user.id,
ownerName: user.name,
ownerEmail: user.email,
ownerAvatar: user.avatar,
};
add(seedCard);
}
}, [add, activeTab, cardLoading, ownerCard, user]);
const handleSignIn = async () => {
if (login) {
await login('google');
}
};
const handleCreateShare = async (e) => {
e.preventDefault();
setShareMessage('');
setShareError('');
if (!user || !ownerCard) {
setShareError('Create your emergency card first before sharing it.');
return;
}
if (!shareEmail.trim()) {
setShareError('Recipient email is required.');
return;
}
const inviteToken = `card_${Math.random().toString(36).slice(2, 10)}_${Date.now().toString(36)}`;
const sharePayload = {
ownerId: user.id,
cardId: ownerCard.id || null,
recipientName: shareName.trim(),
recipientEmail: shareEmail.trim().toLowerCase(),
role: shareRole,
note: shareNote.trim(),
status: 'pending',
inviteToken,
inviteLink: `${window.location.origin}${window.location.pathname}#share=${inviteToken}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
await addShareAccess(sharePayload);
setShareName('');
setShareEmail('');
setShareRole('viewer');
setShareNote('');
setShareMessage('Invite created. Share the link or email it to your recipient.');
};
const handleSendInvite = async (shareItem) => {
setShareMessage('');
setShareError('');
const updated = {
...shareItem,
status: 'sent',
updatedAt: new Date().toISOString(),
};
await updateShareAccess(shareItem.id, updated);
setShareMessage(`Invite marked as sent to ${shareItem.recipientEmail}.`);
};
const handleCopyLink = async (link) => {
try {
await navigator.clipboard.writeText(link);
setShareMessage('Share link copied to clipboard.');
setShareError('');
} catch {
setShareError('Could not copy the link. Please copy it manually.');
}
};
const handleRevoke = async (shareItem) => {
setShareMessage('');
setShareError('');
await removeShareAccess(shareItem.id);
setShareMessage(`Access revoked for ${shareItem.recipientEmail}.`);
};
const handleToggleAccess = async (shareItem) => {
setShareMessage('');
setShareError('');
const nextStatus = shareItem.status === 'revoked' ? 'sent' : 'revoked';
await updateShareAccess(shareItem.id, {
...shareItem,
status: nextStatus,
updatedAt: new Date().toISOString(),
});
setShareMessage(nextStatus === 'revoked' ? 'Access paused.' : 'Access restored.');
};
if (authLoading) return
Signing in...
;
if (!user) {
return (
🆘
Emergency Card
Sign in with Google to securely access your private emergency card.
);
}
return (
{activeTab === 'card' && (
Share access
{sharedAccess.length} shared
Invite a doctor, caregiver, or travel companion to view your emergency card. You can copy a private link or manage access anytime.
{shareMessage &&
{shareMessage}
}
{shareError &&
{shareError}
}
Shared access
{sharedAccess.length === 0 ? (
🔒
No shared access yet
Create an invite above to share your card with someone you trust.
) : (
{sharedAccess.map((item) => (
{item.recipientName || item.recipientEmail}
{item.status}
{item.recipientEmail}
{item.role}
{item.note ? {item.note} : null}
{item.inviteLink}
))}
)}
)}
{activeTab === 'medical' && }
{activeTab === 'contacts' && }
{activeTab === 'insurance' && }
);
}
export default App;
ReactDOM.createRoot(document.getElementById('root')).render();