mirror of
https://github.com/Motion-Games/MotionWebStudio.git
synced 2026-04-21 09:00:53 +02:00
fixed email messages
This commit is contained in:
205
pages/Admin.tsx
205
pages/Admin.tsx
@@ -32,6 +32,7 @@ interface EmailLogEntry {
|
||||
id: string;
|
||||
email_type: string;
|
||||
sent_at: string;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
interface AdminOrder {
|
||||
@@ -49,6 +50,122 @@ interface AdminOrder {
|
||||
emailLogs?: EmailLogEntry[];
|
||||
}
|
||||
|
||||
const getEmailTemplate = (type: string, data: { customer: string, package: string, demoUrl?: string }) => {
|
||||
const baseStyle = "font-family: 'Inter', Helvetica, Arial, sans-serif; line-height: 1.6; color: #1a1a1a; max-width: 600px; margin: 0 auto; padding: 40px 20px; border: 1px solid #f0f0f0; border-radius: 24px; background-color: #ffffff;";
|
||||
const headerStyle = "color: #7c3aed; font-size: 28px; font-weight: 800; margin-bottom: 24px; letter-spacing: -0.02em; border-bottom: 1px solid #f0f0f0; padding-bottom: 20px;";
|
||||
const footerStyle = "margin-top: 40px; padding-top: 24px; border-top: 1px solid #f0f0f0; font-size: 13px; color: #94a3b8;";
|
||||
const buttonStyle = "display: inline-block; background-color: #7c3aed; color: #ffffff !important; padding: 14px 28px; text-decoration: none; border-radius: 12px; font-weight: 700; margin: 20px 0; font-size: 15px;";
|
||||
|
||||
const templates: Record<string, { subject: string, body: string }> = {
|
||||
'Fejlesztés megkezdése': {
|
||||
subject: `Projekt Indítása: Megkezdtük a fejlesztést - ${data.package}`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Örömmel értesítjük, hogy a <strong>${data.package}</strong> csomagjához tartozó fejlesztési folyamat a mai napon hivatalosan is elindult.</p>
|
||||
<p>Szakembereink elkezdték a weboldal vázlatának és design elemeinek kidolgozását. Amint elkészülünk az első megtekinthető demó verzióval, azonnal jelentkezünk a hozzáférési linkkel.</p>
|
||||
<p>Köszönjük a bizalmát!</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'Demó oldal elkészült': {
|
||||
subject: `Elkészült a weboldal demó verziója - ${data.package}`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Jó hírünk van: elkészültünk weboldala első, interaktív bemutató verziójával!</p>
|
||||
<p>A demó oldalt az alábbi biztonságos linken tudja megtekinteni:</p>
|
||||
<div style="text-align: center;">
|
||||
<a href="${data.demoUrl || '#'}" style="${buttonStyle}">DEMÓ MEGTEKINTÉSE</a>
|
||||
</div>
|
||||
<p>Kérjük, nézze át az oldalt, és a MotionWeb ügyfélkapujában a <strong>Rendeléseim</strong> menüpont alatt küldje el visszajelzését, hogy rögzíthessük az esetleges módosítási kéréseit.</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'Módosítások fejlesztése': {
|
||||
subject: `Visszajelzés rögzítve: Módosítások folyamatban`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Köszönjük részletes visszajelzését! A kért módosításokat rögzítettük és szakembereink már dolgoznak azok átvezetésén.</p>
|
||||
<p>Amint a frissített verzió megtekinthető lesz, e-mailben ismét értesíteni fogjuk.</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'1 hete nincs visszajelzés': {
|
||||
subject: `Emlékeztető: Visszajelzés várható a demó oldallal kapcsolatban`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Szeretnénk emlékeztetni, hogy egy héttel ezelőtt küldtük el Önnek a weboldal demó verzióját.</p>
|
||||
<p>Annak érdekében, hogy tartsuk a fejlesztési ütemtervet, kérjük, amint ideje engedi, nézze át a tervet és küldje el véleményét az ügyfélkapun keresztül.</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'2 hete nincs visszajelzés': {
|
||||
subject: `Fontos: Továbblépéshez szükséges visszajelzés hiánya`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Szeretnénk felhívni figyelmét, hogy weboldala demó verziója már két hete várakozik az Ön jóváhagyására.</p>
|
||||
<p>Amennyiben elégedett a látottakkal, kérjük, jelezze azt a felületen a véglegesítés megkezdéséhez. Bármilyen kérdés vagy észrevétel esetén állunk rendelkezésére.</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'Projekt lezárva (Nincs válasz)': {
|
||||
subject: `Értesítés: Projekt adminisztratív lezárása - ${data.package}`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Sajnálattal értesítjük, hogy mivel az elmúlt időszakban többszöri megkeresésünkre sem érkezett válasz, a <strong>${data.package}</strong> projektet a mai napon adminisztratív okokból lezártnak tekintjük.</p>
|
||||
<p>Amennyiben a jövőben folytatni szeretné a fejlesztést, kérjük, vegye fel velünk a kapcsolatot egy új ütemterv egyeztetése érdekében.</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
'Végleges oldal elérhető': {
|
||||
subject: `Gratulálunk! Weboldala elkészült és élesítésre került`,
|
||||
body: `<div style="${baseStyle}">
|
||||
<div style="${headerStyle}">MotionWeb</div>
|
||||
<p>Kedves <strong>${data.customer}</strong>!</p>
|
||||
<p>Örömmel jelentjük, hogy a <strong>${data.package}</strong> projektünk sikeresen befejeződött!</p>
|
||||
<p>A weboldalt élesítettük, így az mostantól minden látogató számára elérhető a végleges domain címen.</p>
|
||||
<p>Köszönjük, hogy minket választott digitális partnerének. Kérjük, amennyiben elégedett volt a munkánkkal, ajánljon minket ismerőseinek is!</p>
|
||||
<div style="${footerStyle}">
|
||||
Üdvözlettel,<br>
|
||||
<strong>Balogh Bence</strong><br>
|
||||
MotionWeb Stúdió | motionweb.hu
|
||||
</div>
|
||||
</div>`
|
||||
}
|
||||
};
|
||||
|
||||
return templates[type] || { subject: 'Értesítés a MotionWeb-től', body: 'Üzenete érkezett a MotionWeb Stúdiótól.' };
|
||||
};
|
||||
|
||||
export const Admin: React.FC = () => {
|
||||
const { user, isAdmin, loading } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
@@ -149,11 +266,17 @@ export const Admin: React.FC = () => {
|
||||
const fetchEmailLogs = async (orderId: string) => {
|
||||
if (!isSupabaseConfigured) return [];
|
||||
try {
|
||||
const { data } = await supabase
|
||||
// Megpróbáljuk lekérni, de ha hiányzik oszlop vagy tábla, hibatűrően kezeljük
|
||||
const { data, error } = await supabase
|
||||
.from('email_log')
|
||||
.select('*')
|
||||
.eq('order_id', orderId)
|
||||
.order('sent_at', { ascending: false });
|
||||
|
||||
if (error) {
|
||||
console.error("Email log fetch error:", error.message);
|
||||
return [];
|
||||
}
|
||||
return data || [];
|
||||
} catch (e) {
|
||||
console.warn("Could not fetch email_log table.");
|
||||
@@ -213,6 +336,10 @@ export const Admin: React.FC = () => {
|
||||
setOrders(prev => prev.map(o => o.id === orderId ? { ...o, status: targetStatus, details: updatedDetails } : o));
|
||||
setViewOrder({ ...viewOrder, status: targetStatus, details: updatedDetails, history: newHist });
|
||||
|
||||
if (demoUrlInput.startsWith('http')) {
|
||||
handleSendEmail('Demó oldal elkészült');
|
||||
}
|
||||
|
||||
alert(`Sikeres mentés és visszajelzés kérése!`);
|
||||
} else {
|
||||
setViewOrder({ ...viewOrder, details: updatedDetails });
|
||||
@@ -240,25 +367,62 @@ export const Admin: React.FC = () => {
|
||||
setEmailSending(emailType);
|
||||
|
||||
try {
|
||||
console.log(`Email notification trigger: ${emailType}`);
|
||||
|
||||
const template = getEmailTemplate(emailType, {
|
||||
customer: viewOrder.customer,
|
||||
package: viewOrder.package,
|
||||
demoUrl: demoUrlInput || viewOrder.details?.demoUrl
|
||||
});
|
||||
|
||||
if (isSupabaseConfigured) {
|
||||
const { error } = await supabase.from('email_log').insert({
|
||||
order_id: viewOrder.id,
|
||||
email_type: emailType
|
||||
// MEGHÍVJUK A FÜGGVÉNYT
|
||||
const response = await supabase.functions.invoke('resend', {
|
||||
body: {
|
||||
to: viewOrder.email,
|
||||
subject: template.subject,
|
||||
html: template.body
|
||||
}
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Supabase hiba kezelése (az invoke hiba objektumot ad vissza, ha a hívás sikertelen)
|
||||
if (response.error) {
|
||||
let errorDetail = response.error.message;
|
||||
if (errorDetail.includes('API kulcs hiányzik')) {
|
||||
throw new Error("HIÁNYZIK A BEÁLLÍTÁS: A Supabase Dashboardon az Edge Functions -> Secrets menüpontban fel kell venni a RESEND_API_KEY kulcsot!");
|
||||
}
|
||||
throw new Error(errorDetail);
|
||||
}
|
||||
|
||||
// A függvény által visszaadott egyedi hiba (ha van)
|
||||
if (response.data && response.data.error) {
|
||||
throw new Error(response.data.error);
|
||||
}
|
||||
|
||||
// SIKERES KÜLDÉS NAPLÓZÁSA (Hibatűrő módon)
|
||||
try {
|
||||
const { error: logError } = await supabase.from('email_log').insert({
|
||||
order_id: viewOrder.id,
|
||||
email_type: emailType,
|
||||
body: template.body
|
||||
});
|
||||
|
||||
if (logError) {
|
||||
console.error("Adatbázis naplózási hiba (lehet, hogy hiányzik a 'body' oszlop):", logError.message);
|
||||
// Itt nem dobunk hibát, mert az email már kiment! Csak logolunk a konzolra.
|
||||
}
|
||||
} catch (dbErr) {
|
||||
console.error("Váratlan hiba az adatbázisba íráskor:", dbErr);
|
||||
}
|
||||
|
||||
const newLogs = await fetchEmailLogs(viewOrder.id);
|
||||
setViewOrder({ ...viewOrder, emailLogs: newLogs });
|
||||
|
||||
alert(`E-mail ("${emailType}") naplózva és kiküldve (szimulált).`);
|
||||
alert(`Sikeres küldés! Az értesítőt kiküldtük ${viewOrder.email} címre.`);
|
||||
} else {
|
||||
alert(`E-mail értesítő előkészítve: "${emailType}"\n\nJelenleg ez a funkció csak placeholder.`);
|
||||
alert(`DEMO MÓD: Tárgy: ${template.subject}`);
|
||||
}
|
||||
} catch (e: any) {
|
||||
alert("Hiba az e-mail naplózásakor: " + e.message);
|
||||
console.error("Hiba az e-mail folyamatban:", e);
|
||||
alert("Hiba az e-mail küldésekor:\n\n" + e.message);
|
||||
} finally {
|
||||
setEmailSending(null);
|
||||
}
|
||||
@@ -468,10 +632,9 @@ export const Admin: React.FC = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* EMAIL NOTIFICATIONS & LOGS COMBINED */}
|
||||
<section className="space-y-8">
|
||||
<div>
|
||||
<h3 className="text-[11px] font-black text-gray-400 uppercase tracking-[0.3em] mb-6 flex items-center gap-2"><Mail className="w-4 h-4" /> E-mail értesítők</h3>
|
||||
<h3 className="text-[11px] font-black text-gray-400 uppercase tracking-[0.3em] mb-6 flex items-center gap-2"><Mail className="w-4 h-4" /> E-mail értesítők (Közvetlen sablonok)</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{[
|
||||
{ label: 'Fejlesztés megkezdése', icon: Rocket },
|
||||
@@ -493,7 +656,9 @@ export const Admin: React.FC = () => {
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<p className="text-xs font-bold text-gray-900">{email.label}</p>
|
||||
<p className="text-[9px] text-gray-400 uppercase font-black tracking-widest mt-0.5">Értesítő küldése</p>
|
||||
<p className="text-[9px] text-gray-400 uppercase font-black tracking-widest mt-0.5">
|
||||
{emailSending === email.label ? 'Küldés folyamatban...' : 'E-mail küldése'}
|
||||
</p>
|
||||
</div>
|
||||
<Send className="w-3 h-3 text-gray-300 group-hover:text-primary group-hover:translate-x-1 transition-all" />
|
||||
</button>
|
||||
@@ -501,7 +666,6 @@ export const Admin: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* IN-PLACE EMAIL LOG */}
|
||||
<div className="bg-purple-50/50 p-8 rounded-[32px] border border-purple-100 shadow-sm">
|
||||
<h4 className="text-[11px] font-black text-purple-600 uppercase tracking-[0.3em] mb-6 flex items-center gap-2"><History className="w-4 h-4" /> Korábban kiküldött e-mailek</h4>
|
||||
<div className="space-y-6 relative before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-0.5 before:bg-purple-200">
|
||||
@@ -510,8 +674,13 @@ export const Admin: React.FC = () => {
|
||||
<div key={log.id} className="relative pl-8">
|
||||
<div className={`absolute left-0 top-1.5 w-6 h-6 rounded-full border-4 border-white shadow-sm z-10 bg-purple-500`} />
|
||||
<div className="text-black">
|
||||
<p className="text-xs font-bold text-gray-900">{log.email_type}</p>
|
||||
<p className="text-[10px] font-black text-purple-400 uppercase tracking-widest mt-0.5">{new Date(log.sent_at).toLocaleString('hu-HU')}</p>
|
||||
<div className="flex justify-between items-start">
|
||||
<p className="text-xs font-bold text-gray-900">{log.email_type}</p>
|
||||
<p className="text-[10px] font-black text-purple-400 uppercase tracking-widest">{new Date(log.sent_at).toLocaleString('hu-HU')}</p>
|
||||
</div>
|
||||
{log.body && (
|
||||
<div className="mt-2 p-3 bg-white border border-purple-100 rounded-xl text-[10px] text-gray-600 max-h-48 overflow-y-auto font-medium" dangerouslySetInnerHTML={{ __html: log.body }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
@@ -557,7 +726,7 @@ export const Admin: React.FC = () => {
|
||||
disabled={savingDemoUrl}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white font-black px-6 py-4 rounded-2xl text-xs uppercase tracking-widest transition-all disabled:opacity-50 shadow-lg shadow-blue-200"
|
||||
>
|
||||
{savingDemoUrl ? 'MENTÉS...' : 'PUBLIKÁLÁS ÉS VISSZAJELZÉS KÉRÉSE'}
|
||||
{savingDemoUrl ? 'MENTÉS...' : 'PUBLIKÁLÁS ÉS ÉRTESÍTÉS'}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user