From ec11ad849825888dd0c72b383ddfe1ef8256b98f Mon Sep 17 00:00:00 2001 From: DanielS Date: Tue, 8 Sep 2026 00:03:27 +0200 Subject: [PATCH] chore: remove all unicode emojis project-wide and sanitize pdf text --- shop/app/my-customers/[id]/page.tsx | 5 ++- shop/components/HeaderWrapper.tsx | 7 +++- .../admin/create-product-dialog.tsx | 39 ++++++++++--------- shop/components/invoice-pdf.tsx | 34 +++++++++------- shop/components/login-form.tsx | 6 ++- shop/components/order-wizard.tsx | 8 ++-- shop/components/tutorial/fetch-data-steps.tsx | 2 +- shop/components/wizard/step-software.tsx | 4 +- shop/components/wizard/toast-notification.tsx | 4 +- shop/lib/actions/auth.ts | 8 ++-- shop/lib/actions/email-templates.ts | 2 +- 11 files changed, 68 insertions(+), 51 deletions(-) diff --git a/shop/app/my-customers/[id]/page.tsx b/shop/app/my-customers/[id]/page.tsx index 0f6c15a..adc198e 100644 --- a/shop/app/my-customers/[id]/page.tsx +++ b/shop/app/my-customers/[id]/page.tsx @@ -193,8 +193,9 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s ) : (
-

- ⚠️ Diese Aktion ist unwiderruflich. Alle personenbezogenen Daten werden überschrieben. +

+ + Diese Aktion ist unwiderruflich. Alle personenbezogenen Daten werden überschrieben.

- ))} + { value: 'one_time', label: 'Einmalig', icon: CreditCard }, + { value: 'monthly', label: 'Monatlich', icon: RefreshCw }, + ].map(opt => { + const IconComponent = opt.icon; + return ( + + ); + })}
diff --git a/shop/components/invoice-pdf.tsx b/shop/components/invoice-pdf.tsx index 2d5bddd..84bf0b5 100644 --- a/shop/components/invoice-pdf.tsx +++ b/shop/components/invoice-pdf.tsx @@ -94,6 +94,14 @@ const styles = StyleSheet.create({ } }); +export const stripEmojis = (text?: string | null): string => { + if (!text) return ''; + return text + .replace(/[\p{Emoji_Presentation}\p{Extended_Pictographic}\uFE0F\u200D]/gu, '') + .replace(/\s{2,}/g, ' ') + .trim(); +}; + export const InvoicePDF = ({ order, orderSnapshot, @@ -105,7 +113,7 @@ export const InvoicePDF = ({ const items = orderSnapshot?.items ?? []; const taxRate = orderSnapshot?.tax_rate ?? 19; const isSubscription = order?.type === 'subscription' || orderSnapshot?.billing_cycle === 'monthly'; - const formattedOrderNumber = (order.order_number || order.id || '').replace(/^BE-/, 'AE-'); + const formattedOrderNumber = stripEmojis((order.order_number || order.id || '').replace(/^BE-/, 'AE-')); const isUpgrade = !!orderSnapshot?.last_license_date; let oneTimeNet = 0; @@ -136,16 +144,16 @@ export const InvoicePDF = ({ const groupedItems: { [key: string]: any[] } = {}; items.forEach((item: any) => { - const devName = item.device_name || 'Kasse 1'; + const devName = stripEmojis(item.device_name || 'Kasse 1'); if (!groupedItems[devName]) { groupedItems[devName] = []; } groupedItems[devName].push(item); }); - const displayPartnerName = partnerCompanyName || order?.partner_company_name; - const displayUserName = partnerUserName || order?.partner_user_name; - const displayUserEmail = partnerUserEmail || order?.partner_user_email; + const displayPartnerName = stripEmojis(partnerCompanyName || order?.partner_company_name); + const displayUserName = stripEmojis(partnerUserName || order?.partner_user_name); + const displayUserEmail = stripEmojis(partnerUserEmail || order?.partner_user_email); return ( @@ -170,11 +178,11 @@ export const InvoicePDF = ({ Endkunde - {customer.company_name} - {customer.first_name || customer.last_name ? {customer.first_name} {customer.last_name} : null} - {customer.address ? {customer.address} : null} - {customer.zip_code || customer.city ? {customer.zip_code} {customer.city} : null} - {customer.vat_id ? USt-IdNr: {customer.vat_id} : null} + {stripEmojis(customer?.company_name)} + {(customer?.first_name || customer?.last_name) ? {stripEmojis(`${customer?.first_name || ''} ${customer?.last_name || ''}`)} : null} + {customer?.address ? {stripEmojis(customer.address)} : null} + {(customer?.zip_code || customer?.city) ? {stripEmojis(`${customer?.zip_code || ''} ${customer?.city || ''}`)} : null} + {customer?.vat_id ? USt-IdNr: {stripEmojis(customer.vat_id)} : null} @@ -205,8 +213,8 @@ export const InvoicePDF = ({ {devItems.map((item: any, idx: number) => ( - - {item.product_name} ({item.category_name}) + + {stripEmojis(item.product_name)} ({stripEmojis(item.category_name)}) {formattedPrice(item.base_price)} {item.billing_interval === 'one_time' ? 'einmalig' : 'mtl.'} @@ -218,7 +226,7 @@ export const InvoicePDF = ({ return ( - + {mod.module_name} {qty > 1 ? `(x${qty})` : ''} + + {stripEmojis(mod.module_name)} {qty > 1 ? `(x${qty})` : ''} +{formattedPrice(price)} mtl. diff --git a/shop/components/login-form.tsx b/shop/components/login-form.tsx index d965bfc..0e1ea6c 100644 --- a/shop/components/login-form.tsx +++ b/shop/components/login-form.tsx @@ -16,6 +16,7 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState, useEffect, useRef, useCallback } from "react"; import { motion, AnimatePresence } from "framer-motion"; +import { Ban } from "lucide-react"; function getDeviceHash(): string { const key = "caspos-device-id"; @@ -227,8 +228,9 @@ export function LoginForm({ />
{errorParam === "gesperrt" && ( -

- 🚫 Ihr Konto wurde gesperrt. Bitte wenden Sie sich an den Administrator. +

+ + Ihr Konto wurde gesperrt. Bitte wenden Sie sich an den Administrator.

)} {messageParam === "concurrent" && ( diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index 381cb2d..707151c 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -8,7 +8,7 @@ import { submitOrder, updateOrder } from '@/lib/actions/orders' import { createEndCustomer } from '@/lib/actions/end-customers' import { isLicenseNumberTaken } from '@/lib/actions/queries' import { Category } from '@/lib/types' -import { Check } from 'lucide-react' +import { Check, Zap } from 'lucide-react' // Modular Step Components import { ProgressStepper } from './wizard/progress-stepper' @@ -991,8 +991,8 @@ export function OrderWizard({ {hasSelection ? ( - - ✓ + + ) : isRequired ? ( @@ -1079,7 +1079,7 @@ export function OrderWizard({ {/* Upgrade-Modus Hinweis-Banner */} {upgradeMode && lockedDeviceId && (
- +

Upgrade-Modus: {lockedDeviceId}

Bereits lizenzierte Module sind ausgegraut und können nicht doppelt gebucht werden.

diff --git a/shop/components/tutorial/fetch-data-steps.tsx b/shop/components/tutorial/fetch-data-steps.tsx index c54aa83..955bad4 100644 --- a/shop/components/tutorial/fetch-data-steps.tsx +++ b/shop/components/tutorial/fetch-data-steps.tsx @@ -156,7 +156,7 @@ export function FetchDataSteps() { -

You're ready to launch your product to the world! 🚀

+

You're ready to launch your product to the world!

); diff --git a/shop/components/wizard/step-software.tsx b/shop/components/wizard/step-software.tsx index de51137..eddce18 100644 --- a/shop/components/wizard/step-software.tsx +++ b/shop/components/wizard/step-software.tsx @@ -93,8 +93,8 @@ export function StepSoftware({ {editingDeviceName && (
- - ✏️ Kasse: "{editingDeviceName}" + + Kasse: "{editingDeviceName}" {onCancelEdit && ( )} diff --git a/shop/lib/actions/auth.ts b/shop/lib/actions/auth.ts index a523ab0..01e0592 100644 --- a/shop/lib/actions/auth.ts +++ b/shop/lib/actions/auth.ts @@ -158,17 +158,17 @@ function get2FAEmailHtml(code: string) {

- ⏱️ Dieser Code ist 15 Minuten gültig.
+ Dieser Code ist 15 Minuten gültig.
Falls Sie diese Anmeldung nicht durchgeführt haben, ändern Sie bitte umgehend Ihr Passwort.

- 🔒 Dieser Code dient der Sicherheit Ihres Kontos. Geben Sie ihn niemals an andere Personen weiter. + Dieser Code dient der Sicherheit Ihres Kontos. Geben Sie ihn niemals an andere Personen weiter.

` - return getBeautifulEmailHtml('🔐 Sicherheitscode', messageHtml) + return getBeautifulEmailHtml('Sicherheitscode', messageHtml) } /** Internal: generates code + sends email (no auth check needed) */ @@ -199,7 +199,7 @@ async function send2FACodeInternal(userId: string, deviceHash: string, email: st // Mail senden await sendMail({ to: email, - subject: '🔐 Ihr Sicherheitscode – CASPOS Shop', + subject: 'Ihr Sicherheitscode – CASPOS Shop', text: `Ihr Sicherheitscode lautet: ${code}\n\nDieser Code ist 15 Minuten gültig.\n\nFalls Sie diese Anmeldung nicht durchgeführt haben, ändern Sie bitte umgehend Ihr Passwort.`, html: get2FAEmailHtml(code), }) diff --git a/shop/lib/actions/email-templates.ts b/shop/lib/actions/email-templates.ts index 6acd090..e6633e0 100644 --- a/shop/lib/actions/email-templates.ts +++ b/shop/lib/actions/email-templates.ts @@ -144,7 +144,7 @@ export function getStatusEmailTemplate( ? `

- 📎 PDF im Anhang verfügbar + PDF im Anhang verfügbar

`