style: pfandlogo.png statt .jpg (transparente Version)

- public/pfandlogo.png ersetzt pfandlogo.jpg
- Alle Referenzen umgestellt (Login, TopNav, SuperAdmin, index.html, manifest.json)
- favicon type=image/png
This commit is contained in:
christian
2026-05-26 13:42:21 +00:00
parent 25ede6f2a3
commit 712afdd253
12 changed files with 63 additions and 2807 deletions

View File

@@ -1,20 +1,47 @@
import nodemailer from 'nodemailer';
import { Resend } from 'resend';
const resend = process.env.RESEND_API_KEY ? new Resend(process.env.RESEND_API_KEY) : null;
const FROM = process.env.MAIL_FROM || 'Pfandsystem Demo <demo@dockly.de>';
export async function sendDemoInviteMail({ to, name, slug, password, loginUrl, days }) {
if (!resend) {
console.log('[mail-dev] Demo-Invite an', to, 'Slug:', slug, 'Pw:', password);
return { dev: true };
let transporter = null;
if (process.env.SMTP_HOST && process.env.SMTP_USER && process.env.SMTP_PASS) {
transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT || '587'),
secure: (process.env.SMTP_SECURE || 'false') === 'true', // 587 = STARTTLS (secure=false)
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
console.log('[mail] SMTP transport aktiv:', process.env.SMTP_HOST);
}
const resend = process.env.RESEND_API_KEY ? new Resend(process.env.RESEND_API_KEY) : null;
async function sendMail({ to, subject, html }) {
if (transporter) {
const info = await transporter.sendMail({ from: FROM, to, subject, html });
console.log('[mail] SMTP sent:', to, 'msgId:', info.messageId);
return { provider: 'smtp', messageId: info.messageId, accepted: info.accepted, rejected: info.rejected };
}
if (resend) {
const r = await resend.emails.send({ from: FROM, to, subject, html });
console.log('[mail] Resend sent:', to, 'id:', r.data?.id);
return { provider: 'resend', id: r.data?.id, error: r.error };
}
console.log('[mail-dev] (kein Provider konfiguriert) ->', to, subject);
return { dev: true };
}
export async function sendDemoInviteMail({ to, name, slug, password, loginUrl, days }) {
const html = `
<div style="font-family:system-ui,Segoe UI,Helvetica,Arial,sans-serif;max-width:560px;margin:auto">
<h2 style="color:#1e293b">Willkommen im Pfandsystem-Demo</h2>
<h2 style="color:#051e23">Willkommen im Pfandsystem-Demo</h2>
<p>Hallo ${name},</p>
<p>dein <strong>${days}-Tage Demo-Zugang</strong> ist bereit. Du kannst alle Funktionen
in Ruhe testen und eigene Beispieldaten anlegen.</p>
<div style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin:16px 0">
<div style="background:#f1f7f8;border:1px solid #b9d2d7;border-radius:8px;padding:16px;margin:16px 0">
<p style="margin:4px 0"><strong>Login-URL:</strong> <a href="${loginUrl}">${loginUrl}</a></p>
<p style="margin:4px 0"><strong>E-Mail:</strong> ${to}</p>
<p style="margin:4px 0"><strong>Passwort:</strong> <code>${password}</code></p>
@@ -23,10 +50,18 @@ export async function sendDemoInviteMail({ to, name, slug, password, loginUrl, d
<p>Bitte aendere dein Passwort nach dem ersten Login.</p>
<p style="color:#64748b;font-size:12px">Diese Mail wurde automatisch versandt vom Pfandsystem-Demo-Portal.</p>
</div>`;
return resend.emails.send({
from: FROM,
to,
subject: `Dein Pfandsystem-Demo-Zugang (${days} Tage)`,
html
});
return sendMail({ to, subject: `Dein Pfandsystem-Demo-Zugang (${days} Tage)`, html });
}
// Test-Endpoint Helper
export async function sendTestMail(to) {
const html = `
<div style="font-family:system-ui,Segoe UI,Helvetica,Arial,sans-serif;max-width:560px;margin:auto">
<h2 style="color:#051e23">Pfandsystem Demo - SMTP-Test</h2>
<p>Diese Test-Mail bestaetigt, dass der Mail-Versand ueber
<code>${process.env.SMTP_HOST || 'kein SMTP'}</code> funktioniert.</p>
<p>Absender: <code>${FROM}</code></p>
<p>Zeitstempel: ${new Date().toISOString()}</p>
</div>`;
return sendMail({ to, subject: 'Pfandsystem Demo - SMTP-Test', html });
}

2785
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "pfandsystem-backend",
"version": "1.0.0",
"type": "module",
"description": "Backend API für Pfandsystem mit MySQL",
"description": "Backend API fuer Pfandsystem mit MySQL",
"main": "server.js",
"scripts": {
"start": "node server.js",
@@ -16,6 +16,7 @@
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.16",
"resend": "^3.0.0",
"express-validator": "^7.0.1"
},

View File

@@ -55,7 +55,12 @@ services:
JWT_SECRET: ${JWT_SECRET}
PORT: 3001
NODE_ENV: production
RESEND_API_KEY: ${RESEND_API_KEY}
RESEND_API_KEY: ${RESEND_API_KEY:-}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_SECURE: ${SMTP_SECURE:-false}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASS: ${SMTP_PASS:-}
MAIL_FROM: ${MAIL_FROM:-Pfandsystem Demo <demo@dockly.de>}
UPLOAD_DIR: /app/uploads
MAX_FILE_SIZE: 10485760

View File

@@ -2,8 +2,8 @@
<html lang="de">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/jpeg" href="/pfandlogo.jpg" />
<link rel="apple-touch-icon" href="/pfandlogo.jpg" />
<link rel="icon" type="image/png" href="/pfandlogo.png" />
<link rel="apple-touch-icon" href="/pfandlogo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="theme-color" content="#051e23" />
<link rel="manifest" href="/manifest.json" />

View File

@@ -7,7 +7,7 @@
"theme_color": "#051e23",
"description": "Digitale Pfand- und Tourenverwaltung",
"icons": [
{ "src": "pfandlogo.jpg", "sizes": "1000x1000", "type": "image/jpeg" },
{ "src": "pfandlogo.png", "sizes": "1000x1000", "type": "image/png" },
{ "src": "icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "icon-512.png", "sizes": "512x512", "type": "image/png" }
]

View File

@@ -7,7 +7,7 @@
"theme_color": "#051e23",
"description": "Digitale Pfand- und Tourenverwaltung",
"icons": [
{ "src": "pfandlogo.jpg", "sizes": "1000x1000", "type": "image/jpeg" },
{ "src": "pfandlogo.png", "sizes": "1000x1000", "type": "image/png" },
{ "src": "icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "icon-512.png", "sizes": "512x512", "type": "image/png" }
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

BIN
public/pfandlogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -27,7 +27,7 @@ export default function Login({ onLogin }) {
<div className="min-h-screen flex items-center justify-center px-4 py-12 bg-gradient-to-br from-slate-50 to-slate-100">
<div className="w-full max-w-sm">
<div className="text-center mb-6">
<img src="/pfandlogo.jpg" alt="Pfandsystem"
<img src="/pfandlogo.png" alt="Pfandsystem"
className="h-20 w-20 mx-auto mb-3 object-contain" />
<h1 className="text-2xl font-bold tracking-tight text-brand-900">Pfandsystem</h1>
<p className="text-sm text-slate-500 mt-1">Demo-Portal</p>

View File

@@ -36,7 +36,7 @@ export default function TopNav({ user, activeView, setActiveView, onLogout }) {
<header className="bg-white border-b border-slate-200 sticky top-0 z-30">
<div className="max-w-6xl mx-auto px-4 sm:px-6 flex items-center h-14">
<div className="flex items-center gap-2 mr-6">
<img src="/pfandlogo.jpg" alt="" className="h-8 w-8 rounded-lg object-contain bg-white ring-1 ring-slate-200 p-0.5" />
<img src="/pfandlogo.png" alt="" className="h-8 w-8 rounded-lg object-contain bg-white ring-1 ring-slate-200 p-0.5" />
<span className="font-semibold text-slate-900">Pfandsystem</span>
{user.tenant_typ === 'demo' && (
<span className="badge-amber ml-2">Demo</span>

View File

@@ -26,7 +26,7 @@ export default function SuperAdmin({ user, onLogout }) {
<header className="bg-white border-b border-slate-200 sticky top-0 z-30">
<div className="max-w-6xl mx-auto px-4 sm:px-6 h-14 flex items-center">
<div className="flex items-center gap-2 flex-1">
<img src="/pfandlogo.jpg" alt="" className="h-8 w-8 rounded-lg object-contain bg-white ring-1 ring-slate-200 p-0.5" />
<img src="/pfandlogo.png" alt="" className="h-8 w-8 rounded-lg object-contain bg-white ring-1 ring-slate-200 p-0.5" />
<span className="font-semibold">Pfandsystem · SuperAdmin</span>
</div>
<div className="text-sm text-slate-500 mr-3 hidden sm:block">{user.email}</div>