feat: Add email field to end_customers table and UI screens
All checks were successful
Staging Build / build (push) Successful in 2m36s

This commit is contained in:
DanielS
2026-06-25 02:29:33 +02:00
parent b9e6559bff
commit b537ca50cf
7 changed files with 38 additions and 3 deletions

View File

@@ -62,6 +62,7 @@ export default function CompanyCustomersPage() {
const [city, setCity] = useState('')
const [vatId, setVatId] = useState('')
const [partnerId, setPartnerId] = useState('')
const [email, setEmail] = useState('')
const [error, setError] = useState<string | null>(null)
const loadData = async () => {
@@ -98,6 +99,7 @@ export default function CompanyCustomersPage() {
setCity(customer ? customer.city || '' : '')
setVatId(customer ? customer.vat_id || '' : '')
setPartnerId(customer ? customer.partner_id || '' : (partners.length > 0 ? partners[0].id : ''))
setEmail(customer ? customer.email || '' : '')
setError(null)
setIsOpen(true)
}
@@ -120,6 +122,7 @@ export default function CompanyCustomersPage() {
zip: zip.trim() || undefined,
city: city.trim() || undefined,
vat_id: vatId.trim() || undefined,
email: email.trim() || undefined,
}
if (editingCustomer) {
@@ -155,7 +158,8 @@ export default function CompanyCustomersPage() {
const personMatch = `${c.first_name || ''} ${c.last_name || ''}`.toLowerCase().includes(q)
const addressMatch = `${c.street || ''} ${c.zip || ''} ${c.city || ''}`.toLowerCase().includes(q)
const partnerMatch = c.partner_name?.toLowerCase().includes(q)
return nameMatch || personMatch || addressMatch || partnerMatch
const emailMatch = c.email?.toLowerCase().includes(q)
return nameMatch || personMatch || addressMatch || partnerMatch || emailMatch
})
@@ -237,6 +241,7 @@ export default function CompanyCustomersPage() {
<tr className="border-b border-slate-200 dark:border-white/10 text-slate-400 text-xs font-semibold uppercase">
<th className="pb-3">Endkunde (Firma / Kontakt)</th>
<th className="pb-3">Lieferadresse</th>
<th className="pb-3">E-Mail</th>
<th className="pb-3">USt-ID</th>
<th className="pb-3">Zugeordneter Partner</th>
<th className="pb-3 text-right">Aktionen</th>
@@ -268,6 +273,9 @@ export default function CompanyCustomersPage() {
<span className="text-slate-400 dark:text-slate-600"></span>
)}
</td>
<td className="py-4 text-sm text-slate-700 dark:text-slate-300">
{customer.email || <span className="text-slate-400 dark:text-slate-600"></span>}
</td>
<td className="py-4 text-sm text-slate-700 dark:text-slate-300">
{customer.vat_id || <span className="text-slate-400 dark:text-slate-600"></span>}
</td>
@@ -425,6 +433,18 @@ export default function CompanyCustomersPage() {
</div>
</div>
<div className="space-y-2">
<Label htmlFor="cust-email">E-Mail</Label>
<Input
id="cust-email"
type="email"
placeholder="kunde@beispiel.de"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="bg-slate-50 dark:bg-white/5 border-slate-200 dark:border-white/10"
/>
</div>
{error && (
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
)}

View File

@@ -21,7 +21,7 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s
const [anonymizing, setAnonymizing] = useState(false)
const [showGdprConfirm, setShowGdprConfirm] = useState(false)
const [form, setForm] = useState({
company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '',
company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', email: '',
})
useEffect(() => {
@@ -37,6 +37,7 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s
street: c.street ?? '',
zip: c.zip ?? '',
city: c.city ?? '',
email: c.email ?? '',
})
setLoading(false)
})
@@ -121,6 +122,7 @@ export default function CustomerDetailPage({ params }: { params: Promise<{ id: s
{ label: 'USt-IdNr.', key: 'vat_id', span: false },
{ label: 'Vorname', key: 'first_name', span: false },
{ label: 'Nachname', key: 'last_name', span: false },
{ label: 'E-Mail', key: 'email', span: true },
{ label: 'Straße & Hausnummer', key: 'street', span: true },
{ label: 'PLZ', key: 'zip', span: false },
{ label: 'Ort', key: 'city', span: false },

View File

@@ -14,7 +14,7 @@ export default function NewCustomerPage() {
const router = useRouter()
const [saving, setSaving] = useState(false)
const [form, setForm] = useState({
company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '',
company_name: '', vat_id: '', first_name: '', last_name: '', street: '', zip: '', city: '', email: '',
})
const handleSave = async () => {
@@ -58,6 +58,7 @@ export default function NewCustomerPage() {
{ label: 'USt-IdNr.', key: 'vat_id', span: false, placeholder: 'DE123456789' },
{ label: 'Vorname', key: 'first_name', span: false, placeholder: '' },
{ label: 'Nachname', key: 'last_name', span: false, placeholder: '' },
{ label: 'E-Mail', key: 'email', span: true, placeholder: 'kunde@beispiel.de' },
{ label: 'Straße & Hausnummer', key: 'street', span: true, placeholder: 'Musterstraße 1' },
{ label: 'PLZ', key: 'zip', span: false, placeholder: '12345' },
{ label: 'Ort', key: 'city', span: false, placeholder: 'Musterstadt' },

View File

@@ -169,6 +169,7 @@ export async function adminCreateEndCustomer(data: {
street?: string
zip?: string
city?: string
email?: string
}) {
const admin = createAdminClient()
const { data: dbData, error } = await admin
@@ -182,6 +183,7 @@ export async function adminCreateEndCustomer(data: {
street: data.street || null,
zip: data.zip || null,
city: data.city || null,
email: data.email || null,
}])
.select()
.single()
@@ -198,6 +200,7 @@ export async function adminUpdateEndCustomer(id: string, data: {
street?: string
zip?: string
city?: string
email?: string
}) {
const admin = createAdminClient()
const { data: dbData, error } = await admin
@@ -211,6 +214,7 @@ export async function adminUpdateEndCustomer(id: string, data: {
street: data.street || null,
zip: data.zip || null,
city: data.city || null,
email: data.email || null,
})
.eq('id', id)
.select()

View File

@@ -15,6 +15,7 @@ export type EndCustomerFormData = {
street?: string
zip?: string
city?: string
email?: string
}
// ─── Lesen ───────────────────────────────────────────────────────────────────
@@ -72,6 +73,7 @@ export async function createEndCustomer(formData: EndCustomerFormData): Promise<
street: formData.street || null,
zip: formData.zip || null,
city: formData.city || null,
email: formData.email || null,
}])
.select()
.single()
@@ -101,6 +103,7 @@ export async function updateEndCustomer(id: string, formData: EndCustomerFormDat
street: formData.street || null,
zip: formData.zip || null,
city: formData.city || null,
email: formData.email || null,
})
.eq('id', id)
@@ -134,6 +137,7 @@ export async function anonymizeEndCustomer(id: string): Promise<void> {
street: null,
zip: null,
city: null,
email: null,
is_anonymized: true,
})
.eq('id', id)

View File

@@ -62,6 +62,7 @@ export type EndCustomer = {
street: string | null
zip: string | null
city: string | null
email?: string | null
is_anonymized: boolean
created_at: string
}

View File

@@ -0,0 +1,3 @@
-- Migration: Add email column to end_customers table
ALTER TABLE public.end_customers
ADD COLUMN IF NOT EXISTS email TEXT;