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.
- ⚠️ Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt.
+
+
Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt.
diff --git a/shop/components/admin/create-product-dialog.tsx b/shop/components/admin/create-product-dialog.tsx
index 4c81c2d..80acb83 100644
--- a/shop/components/admin/create-product-dialog.tsx
+++ b/shop/components/admin/create-product-dialog.tsx
@@ -26,7 +26,7 @@ import {
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
-import { Plus, Trash2, X, PlusCircle } from 'lucide-react'
+import { Plus, Trash2, X, PlusCircle, CreditCard, RefreshCw } from 'lucide-react'
import { createProduct, updateProduct } from '@/lib/actions/products'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator'
@@ -288,23 +288,26 @@ export function CreateProductDialog({
Abrechnungsmodell
{[
- { value: 'one_time', label: 'Einmalig', icon: '💳' },
- { value: 'monthly', label: 'Monatlich', icon: '🔄' },
- ].map(opt => (
- field.onChange(opt.value)}
- className={`flex flex-col items-center gap-1 p-3 rounded-xl border-2 text-sm font-medium transition-all ${
- field.value === opt.value
- ? 'border-primary bg-primary/10 text-primary dark:text-white'
- : 'border-slate-200 dark:border-white/10 bg-slate-50 dark:bg-white/5 text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-white/10'
- }`}
- >
- {opt.icon}
- {opt.label}
-
- ))}
+ { value: 'one_time', label: 'Einmalig', icon: CreditCard },
+ { value: 'monthly', label: 'Monatlich', icon: RefreshCw },
+ ].map(opt => {
+ const IconComponent = opt.icon;
+ return (
+ field.onChange(opt.value)}
+ className={`flex flex-col items-center gap-1 p-3 rounded-xl border-2 text-sm font-medium transition-all ${
+ field.value === opt.value
+ ? 'border-primary bg-primary/10 text-primary dark:text-white'
+ : 'border-slate-200 dark:border-white/10 bg-slate-50 dark:bg-white/5 text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-white/10'
+ }`}
+ >
+
+ {opt.label}
+
+ );
+ })}
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 ? (
-