Merge pull request #121 from Since-3/feature/added-business-settings

added business settings
This commit is contained in:
Rajpreet0 2026-06-15 12:30:49 +02:00 • committed by GitHub
commit 7aba3b6af7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 306 additions and 2 deletions

View file

@ -0,0 +1,55 @@
"use server";
import { prisma } from "@/src/lib/prisma";
import { requireManager } from "@/src/lib/auth/getUser";
import { revalidateTag } from "next/cache";
type ActionResult = { success: boolean; error?: string };
export async function updateBusinessInfo(data: {
businessId: string;
address: string;
email: string;
title: string;
ustId?: string;
banking?: string;
}): Promise<ActionResult> {
try {
const manager = await requireManager();
const business = await prisma.business.findUnique({
where: { id: data.businessId },
select: { managerId: true },
});
if (!business || business.managerId !== manager.id) {
return { success: false, error: "Nicht berechtigt." };
}
const email = data.email.trim();
if (!data.address.trim() || !email || !data.title.trim()) {
return { success: false, error: "Bitte alle Pflichtfelder ausfüllen." };
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
return { success: false, error: "Ungültige E-Mail-Adresse." };
}
await prisma.business.update({
where: { id: data.businessId },
data: {
address: data.address.trim(),
email,
title: data.title.trim(),
ustId: data.ustId?.trim() || null,
banking: data.banking?.trim() || null,
},
});
(revalidateTag as (tag: string, type: "max") => void)(`user-data-${manager.email}`, "max");
return { success: true };
} catch {
return { success: false, error: "Fehler beim Speichern der Business-Daten." };
}
}

View file

@ -0,0 +1,202 @@
"use client";
import { type ReactNode, useState, useTransition } from "react";
import InputComponent from "@/src/components/layout/InputComponent";
import { Button } from "@/src/components/ui/button";
import { updateBusinessInfo } from "../../actions/business-settings-actions";
import { updateProfileInfo } from "../../actions/personal-settings-actions";
import { toast } from "sonner";
export type BusinessSettingsFormProps = {
businessId: string;
name: string;
address: string;
email: string;
title: string;
ustId: string | null;
banking: string | null;
managerTel: string | null;
};
function Card({
title,
subtitle,
children,
}: {
title: string;
subtitle?: string;
children: ReactNode;
}) {
return (
<div className="border border-white/60 bg-white/55 backdrop-blur-xl rounded-2xl shadow-sm p-6 space-y-5">
<div>
<h2 className="text-base font-semibold text-gray-900">{title}</h2>
{subtitle && <p className="text-xs text-gray-400 mt-0.5">{subtitle}</p>}
</div>
{children}
</div>
);
}
const BusinessSettingsForm = ({
businessId,
name,
address: initialAddress,
email: initialEmail,
title: initialTitle,
ustId: initialUstId,
banking: initialBanking,
managerTel: initialTel,
}: BusinessSettingsFormProps) => {
const [pending, startTransition] = useTransition();
const [address, setAddress] = useState(initialAddress);
const [email, setEmail] = useState(initialEmail);
const [title, setTitle] = useState(initialTitle);
const [ustId, setUstId] = useState(initialUstId ?? "");
const [banking, setBanking] = useState(initialBanking ?? "");
const [tel, setTel] = useState(initialTel ?? "");
const handleBusinessSave = () => {
startTransition(async () => {
try {
const result = await updateBusinessInfo({
businessId,
address,
email,
title,
ustId,
banking,
});
if (result.success) {
toast.success("Business-Daten erfolgreich gespeichert.");
} else {
toast.error(result.error ?? "Fehler beim Speichern.");
}
} catch {
toast.error("Fehler beim Speichern.");
}
});
};
const handleTelSave = () => {
startTransition(async () => {
try {
const result = await updateProfileInfo({ tel });
if (result.success) {
toast.success("Geschäftsnummer erfolgreich gespeichert.");
} else {
toast.error(result.error ?? "Fehler beim Speichern.");
}
} catch {
toast.error("Fehler beim Speichern.");
}
});
};
return (
<div className="space-y-6">
{/* Read-only Unternehmensname */}
<div className="border border-white/60 bg-white/55 backdrop-blur-xl rounded-2xl shadow-sm p-6">
<p className="text-xs font-semibold tracking-widest text-gray-400 uppercase mb-1">
Unternehmensname
</p>
<p className="text-xl font-bold text-gray-900">{name}</p>
<p className="text-xs text-gray-400 mt-1">
Der Unternehmensname kann nach der Registrierung nicht mehr geändert werden.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card title="Allgemeine Informationen" subtitle="Titel und Adresse deines Unternehmens">
<div className="space-y-4">
<InputComponent
label="Titel / Kurzname"
type="text"
id="businessTitle"
isLabel
placeholder="Kurzbezeichnung"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<InputComponent
label="Adresse"
type="text"
id="businessAddress"
isLabel
placeholder="Musterstraße 1, 12345 Musterstadt"
value={address}
onChange={(e) => setAddress(e.target.value)}
/>
</div>
<div className="pt-1">
<Button onClick={handleBusinessSave} disabled={pending} size="sm" className="w-fit">
Speichern
</Button>
</div>
</Card>
<Card title="Kontakt & Rechtliches" subtitle="E-Mail, USt-IdNr. und Bankverbindung">
<div className="space-y-4">
<InputComponent
label="Geschäfts-E-Mail"
type="email"
id="businessEmail"
isLabel
placeholder="info@unternehmen.de"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<InputComponent
label="USt-IdNr. (optional)"
type="text"
id="businessUstId"
isLabel
placeholder="DE123456789"
value={ustId}
onChange={(e) => setUstId(e.target.value)}
/>
<InputComponent
label="Bankverbindung (optional)"
type="text"
id="businessBanking"
isLabel
placeholder="IBAN / Kontoinhaber"
value={banking}
onChange={(e) => setBanking(e.target.value)}
/>
</div>
<div className="pt-1">
<Button onClick={handleBusinessSave} disabled={pending} size="sm" className="w-fit">
Speichern
</Button>
</div>
</Card>
<Card title="Geschäftsnummer" subtitle="Telefonnummer des Unternehmens">
<InputComponent
label="Telefonnummer"
type="tel"
id="managerTel"
isLabel
placeholder="+49 000 000000"
value={tel}
onChange={(e) => setTel(e.target.value)}
/>
<div className="pt-1">
<Button
onClick={handleTelSave}
disabled={pending || tel === (initialTel ?? "")}
size="sm"
className="w-fit"
>
Speichern
</Button>
</div>
</Card>
</div>
</div>
);
};
export default BusinessSettingsForm;

View file

@ -1,5 +1,52 @@
const SettingsBusinessPageView = () => {
return <div></div>;
import { requireManager } from "@/src/lib/auth/getUser";
import { prisma } from "@/src/lib/prisma";
import BusinessSettingsForm from "../components/BusinessSettingsForm";
const SettingsBusinessPageView = async () => {
const manager = await requireManager();
const business = await prisma.business.findFirst({
where: { managerId: manager.id },
select: {
id: true,
name: true,
address: true,
email: true,
title: true,
ustId: true,
banking: true,
},
});
if (!business) {
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">Business Einstellungen</h1>
<p className="text-sm text-gray-500 mt-1">Kein Business gefunden.</p>
</div>
</div>
);
}
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">Business Einstellungen</h1>
<p className="text-sm text-gray-500 mt-1">Verwalte die Daten deines Unternehmens</p>
</div>
<BusinessSettingsForm
businessId={business.id}
name={business.name}
address={business.address}
email={business.email}
title={business.title}
ustId={business.ustId}
banking={business.banking}
managerTel={manager.tel}
/>
</div>
);
};
export default SettingsBusinessPageView;