fix: Email Preview Issues - All 5 Fixed! 🔧
## Issues Fixed: ### 1. Button Not Rendering ✅ - Buttons now use custom primary_color - Button text uses button_text_color - Outline buttons use secondary_color - Applied to .button and .button-outline classes ### 2. Double Hash in Order Number ✅ - Changed order_number from "#12345" to "12345" - Templates already have # prefix - Prevents ##12345 display ### 3. Duplicate Icons in Social Selector ✅ - Removed duplicate icon from SelectTrigger - SelectValue already shows the icon - Clean single icon display ### 4. Header/Footer Not Reflecting Customization ✅ - Fetch email settings in EditTemplate - Apply logo_url or header_text to header - Apply footer_text with {current_year} replacement - Render social icons in footer ### 5. Hero Heading Not Using Custom Color ✅ - Apply hero_text_color to all hero card types - .card-hero, .card-success, .card-highlight - All text and headings use custom color ## Preview Now Shows: ✅ Custom logo (if set) or header text ✅ Custom hero gradient colors ✅ Custom hero text color (white/custom) ✅ Custom button colors (primary & secondary) ✅ Custom footer text with {current_year} ✅ Social icons in footer ## Files: - `routes/Settings/Notifications/EditTemplate.tsx` - Preview integration - `routes/Settings/Notifications/EmailCustomization.tsx` - UI fix Everything synced! Preview matches actual emails! 🎉
This commit is contained in:
@@ -38,6 +38,12 @@ export default function EditTemplate() {
|
||||
const [activeTab, setActiveTab] = useState('editor');
|
||||
const [codeMode, setCodeMode] = useState(false);
|
||||
|
||||
// Fetch email customization settings
|
||||
const { data: emailSettings } = useQuery({
|
||||
queryKey: ['email-settings'],
|
||||
queryFn: () => api.get('/notifications/email-settings'),
|
||||
});
|
||||
|
||||
// Fetch template
|
||||
const { data: template, isLoading, error } = useQuery({
|
||||
queryKey: ['notification-template', eventId, channelId],
|
||||
@@ -187,7 +193,7 @@ export default function EditTemplate() {
|
||||
|
||||
// Replace dynamic variables with sample data (not just highlighting)
|
||||
const sampleData: { [key: string]: string } = {
|
||||
order_number: '#12345',
|
||||
order_number: '12345',
|
||||
order_total: '$99.99',
|
||||
order_status: 'Processing',
|
||||
order_date: new Date().toLocaleDateString(),
|
||||
@@ -262,6 +268,33 @@ export default function EditTemplate() {
|
||||
// Parse [card] tags
|
||||
previewBody = parseCardsForPreview(previewBody);
|
||||
|
||||
// Get email settings for preview
|
||||
const settings = emailSettings || {};
|
||||
const primaryColor = settings.primary_color || '#7f54b3';
|
||||
const secondaryColor = settings.secondary_color || '#7f54b3';
|
||||
const heroGradientStart = settings.hero_gradient_start || '#667eea';
|
||||
const heroGradientEnd = settings.hero_gradient_end || '#764ba2';
|
||||
const heroTextColor = settings.hero_text_color || '#ffffff';
|
||||
const buttonTextColor = settings.button_text_color || '#ffffff';
|
||||
const logoUrl = settings.logo_url || '';
|
||||
const headerText = settings.header_text || 'My WordPress Store';
|
||||
const footerText = settings.footer_text || `© ${new Date().getFullYear()} My WordPress Store. All rights reserved.`;
|
||||
const socialLinks = settings.social_links || [];
|
||||
|
||||
// Replace {current_year} in footer
|
||||
const processedFooter = footerText.replace('{current_year}', new Date().getFullYear().toString());
|
||||
|
||||
// Generate social icons HTML
|
||||
const socialIconsHtml = socialLinks.length > 0 ? `
|
||||
<div style="margin-top: 16px;">
|
||||
${socialLinks.map((link: any) => `
|
||||
<a href="${link.url}" style="display: inline-block; margin: 0 8px; text-decoration: none;">
|
||||
<span style="font-size: 24px;">${getSocialIcon(link.platform)}</span>
|
||||
</a>
|
||||
`).join('')}
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -272,17 +305,20 @@ export default function EditTemplate() {
|
||||
.header { padding: 32px; text-align: center; background: #f8f8f8; }
|
||||
.card-gutter { padding: 0 16px; }
|
||||
.card { background: #ffffff; border-radius: 8px; margin-bottom: 24px; padding: 32px 40px; }
|
||||
.card-success { background: #e8f5e9; border: 1px solid #4caf50; }
|
||||
.card-highlight { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #fff; }
|
||||
.card-highlight * { color: #fff !important; }
|
||||
.card-success { background: linear-gradient(135deg, ${heroGradientStart} 0%, ${heroGradientEnd} 100%); color: ${heroTextColor}; }
|
||||
.card-success * { color: ${heroTextColor} !important; }
|
||||
.card-highlight { background: linear-gradient(135deg, ${heroGradientStart} 0%, ${heroGradientEnd} 100%); color: ${heroTextColor}; }
|
||||
.card-highlight * { color: ${heroTextColor} !important; }
|
||||
.card-hero { background: linear-gradient(135deg, ${heroGradientStart} 0%, ${heroGradientEnd} 100%); color: ${heroTextColor}; }
|
||||
.card-hero * { color: ${heroTextColor} !important; }
|
||||
.card-info { background: #f0f7ff; border: 1px solid #0071e3; }
|
||||
.card-warning { background: #fff8e1; border: 1px solid #ff9800; }
|
||||
h1 { font-size: 26px; margin-top: 0; margin-bottom: 16px; color: #333; }
|
||||
h2 { font-size: 18px; margin-top: 0; margin-bottom: 16px; color: #333; }
|
||||
h3 { font-size: 16px; margin-top: 0; margin-bottom: 8px; color: #333; }
|
||||
p { font-size: 16px; line-height: 1.6; color: #555; margin-bottom: 16px; }
|
||||
.button { display: inline-block; background: #7f54b3; color: #fff !important; padding: 14px 28px; border-radius: 6px; text-decoration: none; font-weight: 600; }
|
||||
.button-outline { display: inline-block; background: transparent; color: #7f54b3 !important; padding: 12px 26px; border: 2px solid #7f54b3; border-radius: 6px; text-decoration: none; font-weight: 600; }
|
||||
.button { display: inline-block; background: ${primaryColor}; color: ${buttonTextColor} !important; padding: 14px 28px; border-radius: 6px; text-decoration: none; font-weight: 600; }
|
||||
.button-outline { display: inline-block; background: transparent; color: ${secondaryColor} !important; padding: 12px 26px; border: 2px solid ${secondaryColor}; border-radius: 6px; text-decoration: none; font-weight: 600; }
|
||||
.info-box { background: #f6f6f6; border-radius: 6px; padding: 20px; margin: 16px 0; }
|
||||
.footer { padding: 32px; text-align: center; color: #888; font-size: 13px; }
|
||||
</style>
|
||||
@@ -290,19 +326,33 @@ export default function EditTemplate() {
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<strong style="font-size: 24px; color: #333;">My WordPress Store</strong>
|
||||
${logoUrl ? `<img src="${logoUrl}" alt="${headerText}" style="max-width: 200px; max-height: 60px;">` : `<strong style="font-size: 24px; color: #333;">${headerText}</strong>`}
|
||||
</div>
|
||||
<div class="card-gutter">
|
||||
${previewBody}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>© ${new Date().getFullYear()} My WordPress Store. All rights reserved.</p>
|
||||
<p>${processedFooter}</p>
|
||||
${socialIconsHtml}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
|
||||
// Helper function to get social icon emoji
|
||||
const getSocialIcon = (platform: string) => {
|
||||
const icons: Record<string, string> = {
|
||||
facebook: '📘',
|
||||
twitter: '🐦',
|
||||
instagram: '📷',
|
||||
linkedin: '💼',
|
||||
youtube: '📺',
|
||||
website: '🌐',
|
||||
};
|
||||
return icons[platform] || '🔗';
|
||||
};
|
||||
|
||||
if (!eventId || !channelId) {
|
||||
return (
|
||||
|
||||
@@ -496,10 +496,7 @@ export default function EmailCustomization() {
|
||||
onValueChange={(value) => updateSocialLink(index, 'platform', value)}
|
||||
>
|
||||
<SelectTrigger className="h-9">
|
||||
<div className="flex items-center gap-2">
|
||||
{getSocialIcon(link.platform)}
|
||||
<SelectValue />
|
||||
</div>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="facebook">
|
||||
|
||||
Reference in New Issue
Block a user