import React, { useState, useEffect } from 'react';
import * as jose from 'jose';
// Componente Principal de Diario Personal
const PersonalJournalApp = () => {
const [entries, setEntries] = useState([]);
const [currentEntry, setCurrentEntry] = useState('');
const [mood, setMood] = useState('neutral');
const [isEncrypted, setIsEncrypted] = useState(false);
const [encryptionKey, setEncryptionKey] = useState(null);
// Emociones para seguimiento
const moods = [
{ value: 'muy_feliz', label: '😄 Muy Feliz', color: 'bg-green-200' },
{ value: 'feliz', label: '🙂 Feliz', color: 'bg-green-100' },
{ value: 'neutral', label: '😐 Neutral', color: 'bg-gray-200' },
{ value: 'triste', label: '😔 Triste', color: 'bg-blue-100' },
{ value: 'muy_triste', label: '😢 Muy Triste', color: 'bg-blue-200' }
];
// Generar clave de encriptación
const generateEncryptionKey = async () => {
const key = await jose.generateKeyPair('ES256');
setEncryptionKey(key);
setIsEncrypted(true);
};
// Encriptar entrada
const encryptEntry = async (entry) => {
if (!encryptionKey) {
await generateEncryptionKey();
}
const jwt = await new jose.SignJWT({ entry, mood })
.setProtectedHeader({ alg: 'ES256' })
.setIssuedAt()
.sign(encryptionKey.privateKey);
return jwt;
};
// Guardar entrada
const saveEntry = async () => {
if (!currentEntry.trim()) return;
const encryptedEntry = await encryptEntry(currentEntry);
const newEntry = {
id: Date.now(),
content: encryptedEntry,
date: new Date().toLocaleString(),
mood: mood
};
const updatedEntries = [...entries, newEntry];
setEntries(updatedEntries);
// Guardar en localStorage
localStorage.setItem('journalEntries', JSON.stringify(updatedEntries));
// Limpiar campos
setCurrentEntry('');
setMood('neutral');
};
// Cargar entradas guardadas
useEffect(() => {
const savedEntries = localStorage.getItem('journalEntries');
if (savedEntries) {
setEntries(JSON.parse(savedEntries));
}
}, []);
// Renderizado de la aplicación
return (
<div className="max-w-2xl mx-auto p-6 bg-white shadow-lg rounded-lg">
<h1 className="text-3xl font-bold mb-6 text-center">Mi Diario Personal</h1>
{/* Selector de Estado de Ánimo */}
<div className="mb-4">
<label className="block mb-2">Estado de Ánimo</label>
<div className="flex space-x-2">
{moods.map((moodOption) => (
<button
key={moodOption.value}
onClick={() => setMood(moodOption.value)}
className={`
${moodOption.color}
${mood === moodOption.value ? 'ring-2 ring-blue-500' : ''}
px-3 py-2 rounded-lg text-sm
`}
>
{moodOption.label}
</button>
))}
</div>
</div>
{/* Área de Escritura */}
<textarea
value={currentEntry}
onChange={(e) => setCurrentEntry(e.target.value)}
placeholder="Escribe tu entrada del diario..."
className="w-full h-40 p-3 border rounded-lg mb-4"
/>
{/* Botón de Guardar */}
<button
onClick={saveEntry}
className="w-full bg-blue-500 text-white py-2 rounded-lg hover:bg-blue-600 transition"
>
Guardar Entrada
</button>
{/* Lista de Entradas */}
<div className="mt-6">
<h2 className="text-xl font-semibold mb-4">Mis Entradas</h2>
{entries.map((entry) => (
<div
key={entry.id}
className="bg-gray-100 p-4 rounded-lg mb-3"
>
<p className="text-sm text-gray-600">{entry.date}</p>
<p>Entrada Encriptada</p>
</div>
))}
</div>
</div>
);
};
export default PersonalJournalApp;
How to:
Características Técnicas Destacadas
Seguridad
- Encriptación de entradas usando JWT (JSON Web Tokens)
- Generación de claves criptográficas con biblioteca
jose - Almacenamiento local seguro
Funcionalidades
- Seguimiento de estado de ánimo
- Guardado local de entradas
- Interfaz minimalista y moderna
- Selector de emociones con emojis
Tecnologías
- React
- Tailwind CSS para diseño
- Encriptación con librería
jose
Beneficios Personales
- Práctica de desarrollo web
- Herramienta de autoconocimiento
- Espacio seguro para registro emocional
Próximos Pasos Sugeridos
- Implementar descifrado de entradas
- Añadir exportación/importación
- Integrar análisis de sentimientos
- Implementar sincronización en la nube