Compare commits
4 Commits
073dc99860
...
2b1bb77673
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b1bb77673 | ||
|
|
b692e6d4cf | ||
|
|
0c99da2eeb | ||
|
|
f68d67de43 |
@@ -43,7 +43,20 @@ export async function POST(request: Request) {
|
||||
|
||||
const { to, subject, text, html } = await request.json();
|
||||
try {
|
||||
const info = await sendMail({ to, subject, text, html });
|
||||
const { data: brandData } = await supabase.from('settings').select('primary_color').eq('id', 'branding').maybeSingle();
|
||||
const primaryColor = brandData?.primary_color || '#2563eb';
|
||||
|
||||
const testHtml = html || `
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 8px;">
|
||||
<h2 style="color: ${primaryColor}; margin-bottom: 16px;">Test-E-Mail</h2>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">${text || 'Dies ist eine automatische Test-E-Mail.'}</p>
|
||||
<div style="margin-top: 24px; padding: 12px; background-color: #f8fafc; border-left: 4px solid ${primaryColor}; font-size: 14px; color: #334155;">
|
||||
SMTP-Konfiguration & Branding-Farbe erfolgreich verifiziert.
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const info = await sendMail({ to, subject, text, html: testHtml });
|
||||
return NextResponse.json({ message: 'Email sent', info });
|
||||
} catch (err) {
|
||||
console.error('Mail error', err);
|
||||
|
||||
@@ -295,6 +295,9 @@ export async function POST(request: Request) {
|
||||
|
||||
const itemsSection = buildEmailItemsSection(items);
|
||||
|
||||
const { data: brandData } = await supabase.from('settings').select('primary_color').eq('id', 'branding').maybeSingle();
|
||||
const primaryColor = brandData?.primary_color || '#2563eb';
|
||||
|
||||
const emailTemplate = getOrderEmailTemplate({
|
||||
orderNumber: order.order_number,
|
||||
formattedDate,
|
||||
@@ -303,7 +306,7 @@ export async function POST(request: Request) {
|
||||
totalDetailsHtml,
|
||||
itemsDetailsText: itemsSection.text,
|
||||
itemsDetailsHtml: itemsSection.html
|
||||
}, `${process.env.NEXT_PUBLIC_SITE_URL || 'https://staging.hephex.de'}`, false);
|
||||
}, `${process.env.NEXT_PUBLIC_SITE_URL || 'https://staging.hephex.de'}`, false, primaryColor);
|
||||
|
||||
const { data: bufferData, error: downloadError } = await supabase
|
||||
.storage
|
||||
|
||||
@@ -175,6 +175,7 @@ export function OrderWizard({
|
||||
const [orderNotes, setOrderNotes] = useState<string>('')
|
||||
const [toast, setToast] = useState<{ message: string; type: 'error' | 'success' } | null>(null)
|
||||
const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null)
|
||||
const [showValidationWarning, setShowValidationWarning] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (toast) {
|
||||
@@ -545,14 +546,21 @@ export function OrderWizard({
|
||||
}
|
||||
|
||||
const nextStep = () => {
|
||||
if (step === 3 && allCategoriesFilled && productValidationErrors.length === 0) {
|
||||
const isDirtyNewDevice = (deviceName.trim() !== '' || licenseNumber.trim() !== '' || Object.values(moduleQuantities).some(q => q > 0)) && editingIdx === null
|
||||
if (editingIdx !== null) {
|
||||
addToBasket()
|
||||
} else if (basketItems.length === 0 && hasActiveSelection) {
|
||||
addToBasket()
|
||||
} else if (isDirtyNewDevice && hasActiveSelection) {
|
||||
addToBasket()
|
||||
if (step === 3) {
|
||||
if (isNextStepDisabled && basketItems.length === 0) {
|
||||
setShowValidationWarning(true)
|
||||
return
|
||||
}
|
||||
setShowValidationWarning(false)
|
||||
if (allCategoriesFilled && productValidationErrors.length === 0) {
|
||||
const isDirtyNewDevice = (deviceName.trim() !== '' || licenseNumber.trim() !== '' || Object.values(moduleQuantities).some(q => q > 0)) && editingIdx === null
|
||||
if (editingIdx !== null) {
|
||||
addToBasket()
|
||||
} else if (basketItems.length === 0 && hasActiveSelection) {
|
||||
addToBasket()
|
||||
} else if (isDirtyNewDevice && hasActiveSelection) {
|
||||
addToBasket()
|
||||
}
|
||||
}
|
||||
}
|
||||
setDirection(1)
|
||||
@@ -945,7 +953,7 @@ export function OrderWizard({
|
||||
onClick={() => setActiveCategoryId(cat.id)}
|
||||
className={`flex items-center gap-2.5 p-2.5 rounded-xl border transition-all duration-300 text-left relative overflow-hidden group ${
|
||||
isMissingRequired
|
||||
? 'animate-eye-catcher bg-red-500/10 border-red-500 text-red-400 font-bold shadow-[0_0_20px_rgba(239,68,68,0.4)]'
|
||||
? 'bg-red-500/10 border-red-500/50 text-red-400 font-bold'
|
||||
: isActive
|
||||
? 'bg-primary/10 border-primary text-white shadow-[0_0_15px_rgba(59,130,246,0.2)]'
|
||||
: 'bg-slate-900/50 border-white/5 text-slate-400 hover:bg-slate-900 hover:border-white/20 hover:text-white'
|
||||
@@ -1125,6 +1133,7 @@ export function OrderWizard({
|
||||
addToBasket={addToBasket}
|
||||
isNextStepDisabled={isNextStepDisabled}
|
||||
hasActiveSelection={hasActiveSelection}
|
||||
showValidationWarning={showValidationWarning}
|
||||
nextStep={nextStep}
|
||||
prevStep={prevStep}
|
||||
/>
|
||||
|
||||
@@ -102,7 +102,7 @@ export function StepSoftware({
|
||||
return (
|
||||
<div className={`flex items-center gap-3 p-4 rounded-xl border transition-all ${
|
||||
isMissingRequired
|
||||
? 'animate-eye-catcher bg-red-500/10 border-red-500 text-red-400 font-bold'
|
||||
? 'bg-red-500/10 border-red-500/50 text-red-400 font-bold'
|
||||
: 'bg-white/5 border-white/10'
|
||||
}`}>
|
||||
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
|
||||
|
||||
@@ -45,6 +45,7 @@ interface SummarySidebarProps {
|
||||
addToBasket: () => void
|
||||
isNextStepDisabled: boolean
|
||||
hasActiveSelection: boolean
|
||||
showValidationWarning?: boolean
|
||||
nextStep: () => void
|
||||
prevStep: () => void
|
||||
}
|
||||
@@ -77,6 +78,7 @@ export function SummarySidebar({
|
||||
addToBasket,
|
||||
isNextStepDisabled,
|
||||
hasActiveSelection,
|
||||
showValidationWarning = false,
|
||||
nextStep,
|
||||
prevStep,
|
||||
}: SummarySidebarProps) {
|
||||
@@ -235,7 +237,7 @@ export function SummarySidebar({
|
||||
<p>{updatePriceModifier.label}</p>
|
||||
</div>
|
||||
)}
|
||||
{!allCategoriesFilled && (
|
||||
{!allCategoriesFilled && showValidationWarning && (
|
||||
<div className="text-xs text-red-400 flex items-start gap-2 bg-red-500/10 p-3 rounded-xl border border-red-500/40 animate-eye-catcher">
|
||||
<AlertCircle className="w-4 h-4 shrink-0 text-red-400 mt-0.5" />
|
||||
<div>
|
||||
@@ -244,6 +246,15 @@ export function SummarySidebar({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!allCategoriesFilled && !showValidationWarning && (
|
||||
<div className="text-xs text-slate-400 flex items-start gap-2 bg-slate-900/50 p-2.5 rounded-xl border border-white/5">
|
||||
<AlertCircle className="w-4 h-4 shrink-0 text-slate-500 mt-0.5" />
|
||||
<div>
|
||||
<p className="font-semibold text-[11px] text-slate-300">Pflichtkategorien beachten</p>
|
||||
<p className="text-[11px] text-slate-400">Bitte wählen Sie für die Rot markierten Kategorien ein Produkt aus.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{productValidationErrors.map((err, errIdx) => (
|
||||
<p key={errIdx} className="text-xs text-red-400 flex items-center gap-1 bg-red-500/10 p-2 rounded-lg border border-red-500/20">
|
||||
<AlertCircle className="w-3.5 h-3.5 shrink-0 text-red-400" />
|
||||
|
||||
@@ -14,7 +14,8 @@ interface EmailDetails {
|
||||
export function getOrderEmailTemplate(
|
||||
details: EmailDetails,
|
||||
siteUrl: string,
|
||||
isUpdate: boolean = false
|
||||
isUpdate: boolean = false,
|
||||
primaryColor: string = '#2563eb'
|
||||
) {
|
||||
const title = isUpdate ? 'Anfrage geändert' : 'Anfrage erhalten'
|
||||
const intro = isUpdate
|
||||
@@ -65,7 +66,7 @@ export function getOrderEmailTemplate(
|
||||
|
||||
const html = `
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 8px;">
|
||||
<h2 style="color: #0f172a; margin-bottom: 16px;">${title}</h2>
|
||||
<h2 style="color: ${primaryColor}; margin-bottom: 16px;">${title}</h2>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Hallo,</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">${intro}</p>
|
||||
<div style="background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; margin: 24px 0;">
|
||||
@@ -90,7 +91,7 @@ export function getOrderEmailTemplate(
|
||||
</div>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Die Bestätigung liegt als PDF im Anhang.</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">
|
||||
<a href="${siteUrl}/api/orders/${details.orderNumber}/download" style="color: #3b82f6; text-decoration: underline; font-weight: 500;">Anfragebestätigung PDF herunterladen</a>
|
||||
<a href="${siteUrl}/api/orders/${details.orderNumber}/download" style="color: ${primaryColor}; text-decoration: underline; font-weight: 500;">Anfragebestätigung PDF herunterladen</a>
|
||||
</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5; margin-top: 24px;">Viele Grüße,<br>Dein CASPOS Team</p>
|
||||
</div>
|
||||
|
||||
@@ -117,6 +117,24 @@ export const PRESET_COLOR_SCHEMES: ColorPreset[] = [
|
||||
buttonBg: '#2563eb',
|
||||
ringColor: '#38bdf8',
|
||||
},
|
||||
{
|
||||
id: 'caspos_classic_blue',
|
||||
name: 'CASPOS Classic Blue',
|
||||
description: 'Das originale CASPOS-Blau – vertraut & clean',
|
||||
primary: '#3b82f6',
|
||||
accent: '#60a5fa',
|
||||
success: '#10b981',
|
||||
warning: '#f59e0b',
|
||||
destructive: '#ef4444',
|
||||
bgGlow1: '#3b82f6',
|
||||
bgGlow2: '#1d4ed8',
|
||||
gradientFrom: '#3b82f6',
|
||||
gradientTo: '#2563eb',
|
||||
cardBorder: 'rgba(96, 165, 250, 0.35)',
|
||||
textHighlight: '#bfdbfe',
|
||||
buttonBg: '#3b82f6',
|
||||
ringColor: '#60a5fa',
|
||||
},
|
||||
{
|
||||
id: 'emerald_green',
|
||||
name: 'Emerald Green',
|
||||
|
||||
Reference in New Issue
Block a user