see comments

This commit is contained in:
Rajpreet0 2026-09-27 19:14:28 +02:00
parent 5edd697056
commit b252264211
4 changed files with 34 additions and 9 deletions

View file

@ -14,4 +14,8 @@ begin
); );
return new; return new;
end; end;
$$; $$;
create trigger on_auth_user_created
after insert on auth.users
for each row execute function public.handle_new_user();

View file

@ -1,5 +1,6 @@
"use server"; "use server";
import { createAdminClient } from "@/lib/supabase/admin"; import { createAdminClient } from "@/lib/supabase/admin";
import { verifySession } from "@/lib/supabase/dal";
import { generatePassword } from "@/lib/generate-password"; import { generatePassword } from "@/lib/generate-password";
import * as z from "zod"; import * as z from "zod";
@ -20,6 +21,11 @@ export async function createClient(
formData: FormData formData: FormData
): Promise<CreateClientState> { ): Promise<CreateClientState> {
const session = await verifySession();
if (!session.isAdmin) {
return { error: "Keine Berechtigung." }
}
const validatedFields = CreateClientSchema.safeParse({ const validatedFields = CreateClientSchema.safeParse({
name: formData.get("name"), name: formData.get("name"),
email: formData.get("email") email: formData.get("email")

View file

@ -9,7 +9,7 @@ export async function getClients() {
.eq("role", "client") .eq("role", "client")
.order("name") .order("name")
if (error) return [] if (error) throw new Error(`Failed to load clients: ${error.message}`)
return data return data
} }

View file

@ -1,25 +1,31 @@
"use client" "use client"
import { useState } from "react"; import { useRef, useState } from "react";
import { CheckIcon, CopyIcon } from "lucide-react"; import { CheckIcon, CopyIcon } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Field, FieldLabel } from "@/components/ui/field"; import { Field, FieldLabel } from "@/components/ui/field";
export function CopyField({ label, value }: { label: string; value: string }) { export function CopyField({ label, value }: { label: string; value: string }) {
const [copied, setCopied] = useState(false); const [status, setStatus] = useState<"idle" | "copied" | "error">("idle");
const inputRef = useRef<HTMLInputElement>(null);
async function handleCopy() { async function handleCopy() {
await navigator.clipboard.writeText(value); try {
setCopied(true); await navigator.clipboard.writeText(value);
setTimeout(() => setCopied(false), 1500); setStatus("copied");
} catch {
inputRef.current?.select();
setStatus("error");
}
setTimeout(() => setStatus("idle"), 1500);
} }
return ( return (
<Field> <Field>
<FieldLabel>{label}</FieldLabel> <FieldLabel>{label}</FieldLabel>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Input value={value} readOnly className="focus-visible:ring-0" /> <Input ref={inputRef} value={value} readOnly className="focus-visible:ring-0" />
<Button <Button
type="button" type="button"
variant="outline" variant="outline"
@ -28,9 +34,18 @@ export function CopyField({ label, value }: { label: string; value: string }) {
onClick={handleCopy} onClick={handleCopy}
aria-label={`${label} kopieren`} aria-label={`${label} kopieren`}
> >
{copied ? <CheckIcon className="text-signal-success" /> : <CopyIcon />} {status === "copied" ? (
<CheckIcon className="text-signal-success" />
) : (
<CopyIcon />
)}
</Button> </Button>
</div> </div>
{status === "error" && (
<p className="text-small text-destructive">
Kopieren fehlgeschlagen — Text wurde markiert, bitte manuell kopieren.
</p>
)}
</Field> </Field>
) )
} }