feat: auto-opening brochure modal with mintel/mail delivery
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m53s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m53s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
- implemented BrochureDeliveryEmail template - created AutoBrochureModal wrapper with 5s delay - updated layout.tsx and BrochureCTA to use new success state - added tests/brochure-modal.test.ts e2e test
This commit is contained in:
@@ -1,13 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Document,
|
||||
Page,
|
||||
View,
|
||||
Text,
|
||||
Image,
|
||||
StyleSheet,
|
||||
Font,
|
||||
} from '@react-pdf/renderer';
|
||||
import { Document, Page, View, Text, Image, StyleSheet, Font } from '@react-pdf/renderer';
|
||||
|
||||
// Register fonts (using system fonts for now, can be customized)
|
||||
Font.register({
|
||||
@@ -18,27 +10,43 @@ Font.register({
|
||||
],
|
||||
});
|
||||
|
||||
// Industrial/technical/restrained design - STYLEGUIDE.md compliant
|
||||
// ─── Brand Tokens (matching brochure) ────────────────────────────────────────
|
||||
const C = {
|
||||
navy: '#001a4d',
|
||||
navyDeep: '#000d26',
|
||||
green: '#4da612',
|
||||
greenLight: '#e8f5d8',
|
||||
white: '#FFFFFF',
|
||||
offWhite: '#f8f9fa',
|
||||
gray100: '#f3f4f6',
|
||||
gray200: '#e5e7eb',
|
||||
gray300: '#d1d5db',
|
||||
gray400: '#9ca3af',
|
||||
gray600: '#4b5563',
|
||||
gray900: '#111827',
|
||||
};
|
||||
|
||||
const MARGIN = 56;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
color: '#111827', // Text Primary
|
||||
color: C.gray900,
|
||||
lineHeight: 1.5,
|
||||
backgroundColor: '#FFFFFF',
|
||||
backgroundColor: C.white,
|
||||
paddingTop: 0,
|
||||
paddingBottom: 100,
|
||||
paddingBottom: 80,
|
||||
fontFamily: 'Helvetica',
|
||||
},
|
||||
|
||||
// Hero-style header
|
||||
hero: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
backgroundColor: C.white,
|
||||
paddingTop: 24,
|
||||
paddingBottom: 0,
|
||||
paddingHorizontal: 72,
|
||||
paddingHorizontal: MARGIN,
|
||||
marginBottom: 20,
|
||||
position: 'relative',
|
||||
borderBottomWidth: 0,
|
||||
borderBottomColor: '#e5e7eb',
|
||||
},
|
||||
|
||||
header: {
|
||||
@@ -49,17 +57,17 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
|
||||
logoText: {
|
||||
fontSize: 24,
|
||||
fontSize: 22,
|
||||
fontWeight: 700,
|
||||
color: '#000d26',
|
||||
letterSpacing: 1,
|
||||
color: C.navyDeep,
|
||||
letterSpacing: 2,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
|
||||
docTitle: {
|
||||
fontSize: 10,
|
||||
fontSize: 8,
|
||||
fontWeight: 700,
|
||||
color: '#001a4d',
|
||||
color: C.green,
|
||||
letterSpacing: 2,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
@@ -78,10 +86,10 @@ const styles = StyleSheet.create({
|
||||
height: 120,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: 8,
|
||||
borderRadius: 4,
|
||||
borderWidth: 1,
|
||||
borderColor: '#e5e7eb',
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderColor: C.gray200,
|
||||
backgroundColor: C.white,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
|
||||
@@ -93,7 +101,7 @@ const styles = StyleSheet.create({
|
||||
productName: {
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
color: '#000d26',
|
||||
color: C.navyDeep,
|
||||
marginBottom: 0,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: -0.5,
|
||||
@@ -101,7 +109,7 @@ const styles = StyleSheet.create({
|
||||
|
||||
productMeta: {
|
||||
fontSize: 10,
|
||||
color: '#4b5563',
|
||||
color: C.gray600,
|
||||
fontWeight: 700,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 1,
|
||||
@@ -115,13 +123,13 @@ const styles = StyleSheet.create({
|
||||
|
||||
noImage: {
|
||||
fontSize: 8,
|
||||
color: '#9ca3af',
|
||||
color: C.gray400,
|
||||
textAlign: 'center',
|
||||
},
|
||||
|
||||
// Content Area
|
||||
content: {
|
||||
paddingHorizontal: 72,
|
||||
paddingHorizontal: MARGIN,
|
||||
},
|
||||
|
||||
// Content sections
|
||||
@@ -130,40 +138,40 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
|
||||
sectionTitle: {
|
||||
fontSize: 14,
|
||||
fontSize: 8,
|
||||
fontWeight: 700,
|
||||
color: '#000d26', // Primary Dark
|
||||
marginBottom: 8,
|
||||
color: C.green,
|
||||
marginBottom: 6,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: -0.2,
|
||||
letterSpacing: 1.5,
|
||||
},
|
||||
|
||||
sectionAccent: {
|
||||
width: 30,
|
||||
height: 3,
|
||||
backgroundColor: '#82ed20', // Accent Green
|
||||
height: 2,
|
||||
backgroundColor: C.green,
|
||||
marginBottom: 8,
|
||||
borderRadius: 1.5,
|
||||
borderRadius: 1,
|
||||
},
|
||||
|
||||
description: {
|
||||
fontSize: 11,
|
||||
fontSize: 10,
|
||||
lineHeight: 1.7,
|
||||
color: '#4b5563', // Text Secondary
|
||||
color: C.gray600,
|
||||
},
|
||||
|
||||
// Technical data table
|
||||
specsTable: {
|
||||
marginTop: 8,
|
||||
border: '1px solid #e5e7eb',
|
||||
borderRadius: 8,
|
||||
marginTop: 4,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
|
||||
specsTableRow: {
|
||||
flexDirection: 'row',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#e5e7eb',
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: C.gray200,
|
||||
},
|
||||
|
||||
specsTableRowLast: {
|
||||
@@ -172,83 +180,85 @@ const styles = StyleSheet.create({
|
||||
|
||||
specsTableLabelCell: {
|
||||
flex: 1,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 16,
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRightWidth: 1,
|
||||
borderRightColor: '#e5e7eb',
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 12,
|
||||
backgroundColor: C.offWhite,
|
||||
borderRightWidth: 0.5,
|
||||
borderRightColor: C.gray200,
|
||||
},
|
||||
|
||||
specsTableValueCell: {
|
||||
flex: 1,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
|
||||
specsTableLabelText: {
|
||||
fontSize: 9,
|
||||
fontSize: 8,
|
||||
fontWeight: 700,
|
||||
color: '#000d26',
|
||||
color: C.navyDeep,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
specsTableValueText: {
|
||||
fontSize: 10,
|
||||
color: '#111827',
|
||||
fontWeight: 500,
|
||||
fontSize: 9,
|
||||
color: C.gray900,
|
||||
fontWeight: 400,
|
||||
},
|
||||
|
||||
// Categories
|
||||
categories: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 8,
|
||||
gap: 6,
|
||||
},
|
||||
|
||||
categoryTag: {
|
||||
backgroundColor: '#f8f9fa',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
border: '1px solid #e5e7eb',
|
||||
borderRadius: 100,
|
||||
backgroundColor: C.offWhite,
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderWidth: 0.5,
|
||||
borderColor: C.gray200,
|
||||
borderRadius: 3,
|
||||
},
|
||||
|
||||
categoryText: {
|
||||
fontSize: 8,
|
||||
color: '#4b5563',
|
||||
fontSize: 7,
|
||||
color: C.gray600,
|
||||
fontWeight: 700,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
// Footer
|
||||
// Footer — matches brochure style
|
||||
footer: {
|
||||
position: 'absolute',
|
||||
bottom: 40,
|
||||
left: 72,
|
||||
right: 72,
|
||||
bottom: 28,
|
||||
left: MARGIN,
|
||||
right: MARGIN,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: 24,
|
||||
borderTop: '1px solid #e5e7eb',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 2,
|
||||
borderTopColor: C.green,
|
||||
},
|
||||
|
||||
footerText: {
|
||||
fontSize: 8,
|
||||
color: '#9ca3af',
|
||||
fontWeight: 500,
|
||||
fontSize: 7,
|
||||
color: C.gray400,
|
||||
fontWeight: 400,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 1,
|
||||
letterSpacing: 0.8,
|
||||
},
|
||||
|
||||
footerBrand: {
|
||||
fontSize: 10,
|
||||
fontSize: 9,
|
||||
fontWeight: 700,
|
||||
color: '#000d26',
|
||||
color: C.navyDeep,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 1,
|
||||
letterSpacing: 1.5,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -302,10 +312,7 @@ const getLabels = (locale: 'en' | 'de') => {
|
||||
return labels[locale];
|
||||
};
|
||||
|
||||
export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
product,
|
||||
locale,
|
||||
}) => {
|
||||
export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({ product, locale }) => {
|
||||
const labels = getLabels(locale);
|
||||
|
||||
return (
|
||||
@@ -317,9 +324,7 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
<View>
|
||||
<Text style={styles.logoText}>KLZ</Text>
|
||||
</View>
|
||||
<Text style={styles.docTitle}>
|
||||
{labels.productDatasheet}
|
||||
</Text>
|
||||
<Text style={styles.docTitle}>{labels.productDatasheet}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.productRow}>
|
||||
@@ -328,7 +333,8 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
<View style={styles.categories}>
|
||||
{product.categories.map((cat, index) => (
|
||||
<Text key={index} style={styles.productMeta}>
|
||||
{cat.name}{index < product.categories.length - 1 ? ' • ' : ''}
|
||||
{cat.name}
|
||||
{index < product.categories.length - 1 ? ' • ' : ''}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
@@ -337,12 +343,8 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
</View>
|
||||
<View style={styles.productImageCol}>
|
||||
{product.featuredImage ? (
|
||||
<Image
|
||||
src={product.featuredImage}
|
||||
style={styles.heroImage}
|
||||
/>
|
||||
<Image src={product.featuredImage} style={styles.heroImage} />
|
||||
) : (
|
||||
|
||||
<Text style={styles.noImage}>{labels.noImage}</Text>
|
||||
)}
|
||||
</View>
|
||||
@@ -356,7 +358,11 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
<Text style={styles.sectionTitle}>{labels.description}</Text>
|
||||
<View style={styles.sectionAccent} />
|
||||
<Text style={styles.description}>
|
||||
{stripHtml(product.applicationHtml || product.shortDescriptionHtml || product.descriptionHtml)}
|
||||
{stripHtml(
|
||||
product.applicationHtml ||
|
||||
product.shortDescriptionHtml ||
|
||||
product.descriptionHtml,
|
||||
)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
@@ -372,17 +378,14 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
||||
key={index}
|
||||
style={[
|
||||
styles.specsTableRow,
|
||||
index === product.attributes.length - 1 &&
|
||||
styles.specsTableRowLast,
|
||||
index === product.attributes.length - 1 && styles.specsTableRowLast,
|
||||
]}
|
||||
>
|
||||
<View style={styles.specsTableLabelCell}>
|
||||
<Text style={styles.specsTableLabelText}>{attr.name}</Text>
|
||||
</View>
|
||||
<View style={styles.specsTableValueCell}>
|
||||
<Text style={styles.specsTableValueText}>
|
||||
{attr.options.join(', ')}
|
||||
</Text>
|
||||
<Text style={styles.specsTableValueText}>{attr.options.join(', ')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user