sepehr 640fcb26f7 fix: improve note interactions and markdown LaTeX support
## Bug Fixes

### Note Card Actions
- Fix broken size change functionality (missing state declaration)
- Implement React 19 useOptimistic for instant UI feedback
- Add startTransition for non-blocking updates
- Ensure smooth animations without page refresh
- All note actions now work: pin, archive, color, size, checklist

### Markdown LaTeX Rendering
- Add remark-math and rehype-katex plugins
- Support inline equations with dollar sign syntax
- Support block equations with double dollar sign syntax
- Import KaTeX CSS for proper styling
- Equations now render correctly instead of showing raw LaTeX

## Technical Details

- Replace undefined currentNote references with optimistic state
- Add optimistic updates before server actions for instant feedback
- Use router.refresh() in transitions for smart cache invalidation
- Install remark-math, rehype-katex, and katex packages

## Testing

- Build passes successfully with no TypeScript errors
- Dev server hot-reloads changes correctly
2026-01-09 22:13:49 +01:00

65 lines
2.1 KiB
TypeScript

import nodemailer from 'nodemailer';
import { getSystemConfig } from './config';
interface MailOptions {
to: string;
subject: string;
html: string;
}
export async function sendEmail({ to, subject, html }: MailOptions) {
const config = await getSystemConfig();
const host = config.SMTP_HOST || process.env.SMTP_HOST;
const port = parseInt(config.SMTP_PORT || process.env.SMTP_PORT || '587');
const user = (config.SMTP_USER || process.env.SMTP_USER || '').trim();
const pass = (config.SMTP_PASS || process.env.SMTP_PASS || '').trim();
const from = config.SMTP_FROM || process.env.SMTP_FROM || 'noreply@memento.app';
// Options de sécurité
const forceSecure = config.SMTP_SECURE === 'true'; // Forcé par l'admin
const isPort465 = port === 465;
// Si secure n'est pas forcé, on déduit du port (465 = secure, autres = starttls)
const secure = forceSecure || isPort465;
const ignoreCerts = config.SMTP_IGNORE_CERT === 'true';
const transporter = nodemailer.createTransport({
host: host || undefined,
port: port || undefined,
secure: secure || false,
auth: { user, pass },
// Force IPv4 pour éviter les problèmes de résolution DNS/Docker
family: 4,
// Force AUTH LOGIN pour meilleure compatibilité (Mailcow, Exchange) vs PLAIN par défaut
authMethod: 'LOGIN',
// Timeout généreux
connectionTimeout: 10000,
tls: {
// Si on ignore les certs, on autorise tout.
// Sinon on laisse les défauts stricts de Node.
rejectUnauthorized: !ignoreCerts,
// Compatibilité vieux serveurs si besoin (optionnel, activé si ignoreCerts pour maximiser les chances)
ciphers: ignoreCerts ? 'SSLv3' : undefined
}
} as any);
try {
await transporter.verify();
const info = await transporter.sendMail({
from: `"Memento App" <${from}>`,
to,
subject,
html,
});
return { success: true, messageId: info.messageId };
} catch (error: any) {
console.error("❌ Erreur SMTP:", error);
return {
success: false,
error: `Erreur envoi: ${error.message} (Code: ${error.code})`
};
}
}