stadtwerke/innungsapp/apps/admin/app/[slug]/dashboard/einstellungen/page.tsx

143 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { trpc } from '@/lib/trpc-client'
import { useState } from 'react'
export default function EinstellungenPage() {
const { data: org, isLoading } = trpc.organizations.me.useQuery()
const updateMutation = trpc.organizations.update.useMutation()
const avvMutation = trpc.organizations.acceptAvv.useMutation()
const [name, setName] = useState('')
const [contactEmail, setContactEmail] = useState('')
if (isLoading) return <div className="text-gray-500">Wird geladen...</div>
if (!org) return null
return (
<div className="max-w-2xl space-y-8">
<h1 className="text-2xl font-bold text-gray-900">Einstellungen</h1>
{/* Org Settings */}
<div className="bg-white rounded-lg border p-6 space-y-4">
<h2 className="font-semibold text-gray-900">Innung</h2>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Name der Innung</label>
<input
defaultValue={org.name}
onChange={(e) => setName(e.target.value)}
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Kontakt-E-Mail</label>
<input
type="email"
defaultValue={org.contactEmail ?? ''}
onChange={(e) => setContactEmail(e.target.value)}
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent"
/>
</div>
<button
onClick={() => updateMutation.mutate({ name: name || undefined, contactEmail: contactEmail || undefined })}
disabled={updateMutation.isPending}
className="bg-brand-500 text-white px-4 py-2 rounded-lg text-sm font-medium hover:bg-brand-600 disabled:opacity-60 transition-colors"
>
{updateMutation.isPending ? 'Wird gespeichert...' : 'Speichern'}
</button>
{updateMutation.isSuccess && (
<p className="text-sm text-green-600">Einstellungen gespeichert </p>
)}
</div>
{/* AVV */}
<div className="bg-white rounded-lg border p-6 space-y-4">
<h2 className="font-semibold text-gray-900">Auftragsverarbeitungsvertrag (AVV)</h2>
<p className="text-sm text-gray-600">
Der AVV regelt die Verarbeitung personenbezogener Daten im Auftrag Ihrer Innung
durch InnungsApp GmbH gemäß Art. 28 DSGVO.
</p>
<a
href="/avv.pdf"
download
className="inline-flex items-center gap-2 text-sm text-brand-600 hover:underline"
>
📄 AVV als PDF herunterladen
</a>
{org.avvAccepted ? (
<div className="bg-green-50 border border-green-200 rounded-lg p-4">
<p className="text-sm text-green-700 font-medium">
AVV akzeptiert am {org.avvAcceptedAt?.toLocaleDateString('de-DE')}
</p>
</div>
) : (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 space-y-3">
<p className="text-sm text-yellow-800 font-medium">
Der AVV muss vor dem Go-Live akzeptiert werden.
</p>
<label className="flex items-start gap-2 cursor-pointer">
<input
type="checkbox"
id="avv-check"
className="mt-0.5 rounded border-gray-300"
/>
<span className="text-sm text-gray-700">
Ich bestätige, dass ich den AVV gelesen habe und im Namen der Innung akzeptiere.
</span>
</label>
<button
onClick={() => {
const cb = document.getElementById('avv-check') as HTMLInputElement
if (!cb.checked) { alert('Bitte bestätigen Sie den AVV.'); return }
avvMutation.mutate()
}}
disabled={avvMutation.isPending}
className="bg-brand-500 text-white px-4 py-2 rounded-lg text-sm font-medium hover:bg-brand-600 disabled:opacity-60 transition-colors"
>
AVV verbindlich akzeptieren
</button>
</div>
)}
</div>
{/* Registrierungslink */}
<div className="bg-white rounded-lg border p-6 space-y-4">
<h2 className="font-semibold text-gray-900">Registrierungslink</h2>
<p className="text-sm text-gray-600">
Teilen Sie diesen Link mit neuen Mitgliedern. Sie können sich damit selbst registrieren
und erhalten einen Aktivierungslink per E-Mail.
</p>
<div className="flex gap-2">
<input
readOnly
value={`${typeof window !== 'undefined' ? window.location.origin : ''}/registrierung/${org.slug}`}
className="flex-1 px-3 py-2 border border-gray-200 rounded-lg text-sm bg-gray-50 text-gray-700 focus:outline-none"
/>
<button
type="button"
onClick={() =>
navigator.clipboard.writeText(
`${window.location.origin}/registrierung/${org.slug}`
)
}
className="px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors whitespace-nowrap"
>
Kopieren
</button>
</div>
</div>
{/* Plan Info */}
<div className="bg-white rounded-lg border p-6">
<h2 className="font-semibold text-gray-900 mb-2">Plan</h2>
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-brand-100 text-brand-700 capitalize">
{org.plan}
</span>
<p className="text-sm text-gray-500 mt-2">
Für Upgrades oder Fragen zum Plan: kontakt@innungsapp.de
</p>
</div>
</div>
)
}