Sidebar: Projekt-Admin entfernt (Admin-Panel abgeschaltet)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-02 03:55:04 +00:00
1 parent feda436936
commit 36eb55b81b
12 files changed
+12 -45

No files matched your search

-18
View File
@@ -15,13 +15,11 @@ import {
IconLogout,
IconLayoutSidebarLeftCollapse,
IconLayoutSidebarLeftExpand,
IconExternalLink,
IconMessages,
IconReceiptRefund,
IconDiscount,
IconMailCog,
} from '@tabler/icons-react'
import { openProjectAdmin } from '../lib/employeeAdminApi'
import { serverpulsApi } from '../lib/serverpulsApi'
import { startsCollapsed } from '../lib/sidebar'
import { buildNavLinks } from '../lib/navLinks'
@@ -49,7 +47,6 @@ export default function Sidebar() {
const navigate = useNavigate()
const location = useLocation()
const [collapsed, setCollapsed] = useState(() => startsCollapsed())
const [switching, setSwitching] = useState(false)
const [pulseLevel, setPulseLevel] = useState('ok')
const counts = useSidebarCounts()
@@ -67,11 +64,6 @@ export default function Sidebar() {
return () => { dead = true; clearInterval(iv) }
}, [isAdmin])
const handleProjectAdmin = async () => {
setSwitching(true)
await openProjectAdmin()
}
const handleLogout = async () => {
await logout()
navigate('/login')
@@ -139,16 +131,6 @@ export default function Sidebar() {
</Link>
)),
])}
<button
type="button"
className="side-link side-link-button"
onClick={handleProjectAdmin}
disabled={switching}
title="Projekt-Admin"
>
<IconExternalLink />
<span className="side-link-label">Projekt-Admin</span>
</button>
</div>
</nav>
+1 -1
View File
@@ -13,7 +13,7 @@ const staffOf = (by) => (by && by !== 'customer' && by !== 'system' ? ` · ${by}
const toCents = (value) => Math.round(Number(value) * 100)
/**
* Antrag auf Uebernahmegutschrift: Pruefung und Entscheidung wie im frueheren Admin-Panel (public/admin.js 684-906).
* Antrag auf Uebernahmegutschrift: Pruefung und Entscheidung wie im frueheren Admin-Panel.
* Waehrend einer Entscheidung sind alle Knoepfe gesperrt (busyRef verhindert auch Doppelklicks vor dem Neuzeichnen).
*/
export default function CreditDetail({ id, onClose, onChanged, onOpen }) {
+1 -1
View File
@@ -10,7 +10,7 @@ import '../../styles/admin-areas.css'
const MONTHS = Array.from({ length: 12 }, (_, i) => i + 1)
/**
* "Neues Angebot" wie im frueheren Admin-Panel (public/admin.js 1131-1311). Der Kontext (Abo, offene Angebote, Preise)
* "Neues Angebot" wie im frueheren Admin-Panel. Der Kontext (Abo, offene Angebote, Preise)
* wird genau einmal je gewaehltem Kunden geladen; beim Wechsel sofort geleert, spaete Antworten verworfen. Vorschau
* und Speichern erst mit dem Kontext des aktuellen Kunden.
*/
+2 -2
View File
@@ -10,7 +10,7 @@ export function sortChats(chats) {
})
}
/** Ergebnis des Mail-Hinweises an den Kunden (K17), Texte wie im Admin-Panel. */
/** Ergebnis des Mail-Hinweises an den Kunden (K17), Texte wie im frueheren Admin-Panel. */
export function noticeText(notice, time) {
if (!notice) return ''
if (notice.sent) return `E-Mail-Hinweis an ${notice.to} gesendet (${time})`
@@ -30,7 +30,7 @@ export function messageMeta(msg, customerName) {
const FULL_REFRESH_MS = 10 * 60 * 1000
export const needsFullRefresh = (lastFullAt, now) => now - lastFullAt >= FULL_REFRESH_MS
/** Eindeutige Beschriftung fuer "Neue Nachricht an Kunde…" wie im Admin-Panel: Name · E-Mail · Kd.-Nr. */
/** Eindeutige Beschriftung fuer "Neue Nachricht an Kunde…" wie im frueheren Admin-Panel: Name · E-Mail · Kd.-Nr. */
export function customerPickLabel(c) {
return [c.name, c.email, c.code ? `Kd.-Nr. ${c.code}` : ''].filter(Boolean).join(' · ') || c.$id
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { fmtDate, formatCents } from './format'
// Uebernahmegutschriften: Texte und Pruefungen wortgleich aus dem Admin-Panel (public/admin.js 535-906).
// Uebernahmegutschriften: Texte und Pruefungen wortgleich aus dem frueheren Admin-Panel des Portals.
export const CREDIT_STATUS = {
offen: { tone: 'warn', label: 'Zu prüfen' },
-10
View File
@@ -38,13 +38,3 @@ export function updateEmployeeWithLogin(employeeId, payload) {
export function deleteEmployeeWithLogin(employeeId) {
return adminFetch(`/api/admin/employees/${employeeId}`, { method: 'DELETE' })
}
/** Wechsel ins Projekt-Admin ohne zweiten Login: Einmal-Link holen und im selben Tab oeffnen. */
export async function openProjectAdmin() {
try {
const { openUrl } = await adminFetch('/api/admin/switch-link', { method: 'POST', body: {} })
window.location.assign(openUrl)
} catch {
window.location.assign('https://project.webklar.com/login.html')
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
// Gemeinsame Formate fuer die Bereiche aus dem Admin-Panel (Gutschriften, Angebote, E-Mail-Speicher).
// Gemeinsame Formate fuer die Bereiche aus dem frueheren Admin-Panel (Gutschriften, Angebote, E-Mail-Speicher).
// Deutsche Zeit (Europe/Berlin), Euro wie Intl de-DE. Rein, unter Node testbar.
const EURO = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' })
@@ -30,7 +30,7 @@ export function fmtDate(value) {
return `${p.day}.${p.month}.${p.year}`
}
/** dd.mm.yy, hh:mm (deutsche Zeit) wie im Admin-Panel; leer -> "–" */
/** dd.mm.yy, hh:mm (deutsche Zeit) wie im frueheren Admin-Panel; leer -> "–" */
export function fmtDateTime(value) {
if (!valid(value)) return value ? String(value) : '–'
const p = parts(value, { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit' })
+2 -2
View File
@@ -1,6 +1,6 @@
import { berlinYmd, fmtBerlin, fmtDate, fmtYmd, formatCents, PRODUCT_LABEL } from './format'
// Abo-Angebote: Texte, Rabattende und Formularpruefung wortgleich aus dem Admin-Panel (public/admin.js 984-1317).
// Abo-Angebote: Texte, Rabattende und Formularpruefung wortgleich aus dem frueheren Admin-Panel des Portals.
// "today" ist der Kalendertag in Deutschland (YYYY-MM-DD) und fuer Tests injizierbar.
export const OFFER_STATUS = {
@@ -52,7 +52,7 @@ export function discountLine(o, today = todayBerlin()) {
export const isRunning = (ctx, productKey) => Boolean(ctx?.subscription?.active && ctx.subscription.productKey === productKey)
/**
* Pruefung und Vorschau des Formulars "Neues Angebot" (admin.js renderOfferPreview).
* Pruefung und Vorschau des Formulars "Neues Angebot" (wie im frueheren Admin-Panel).
* -> { errors, running, saveLabel, previewLines }; Speichern nur ohne errors.
*/
export function evaluateOfferForm(ctx, f, today = todayBerlin()) {
+1 -1
View File
@@ -1,6 +1,6 @@
import { fmtDate } from './format'
// E-Mail-Speicher (Zusatzspeicher-Aufgaben in konsoleH): Texte wortgleich aus dem Admin-Panel (public/admin.js 908-982).
// E-Mail-Speicher (Zusatzspeicher-Aufgaben in konsoleH): Texte wortgleich aus dem frueheren Admin-Panel des Portals.
const GB_INCLUDED = 5
const GB_PER_UNIT = 5
+1 -1
View File
@@ -21,7 +21,7 @@
.woms-chat .chat-bubble.mine { align-self: flex-end; background: var(--accent-soft); border: 1px solid rgba(16, 185, 129, 0.35); }
.woms-chat .chat-meta { display: block; margin-top: 4px; font-size: 11.5px; color: var(--text-muted); }
.woms-chat .chat-notice { font-size: 12px; }
/* Eingabefeld: Grundstil wie im Admin-Panel (chat-composer.css setzt nur das Layout) */
/* Eingabefeld: Grundstil wie im frueheren Admin-Panel (chat-composer.css setzt nur das Layout) */
.woms-chat .chat-input-row textarea {
resize: none; min-height: 46px; max-height: 130px; padding: 11px 14px; border-radius: 14px;
border: 1px solid var(--border); background: var(--surface-2); color: var(--text); font: inherit; line-height: 1.4;
-5
View File
@@ -843,11 +843,6 @@ textarea.form-control {
}
.side-link svg { width: 20px; height: 20px; flex-shrink: 0; }
.side-link:hover { background: var(--surface-2); color: var(--text); }
.side-link-button {
background: transparent; border: none; font: inherit; cursor: pointer;
width: calc(100% - 2 * var(--sp-1)); text-align: left;
}
.side-link-button:disabled { opacity: 0.6; cursor: progress; }
.side-link-paused, .side-link-paused:hover { opacity: 0.45; cursor: not-allowed; background: transparent; color: var(--text-muted); }
.side-link.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.side-sublink { padding-left: calc(var(--sp-3) + 18px); font-size: 13.5px; }
+1 -1
View File
@@ -2,7 +2,7 @@ import test from 'node:test'
import assert from 'node:assert/strict'
import { loadModule } from './load.mjs'
// Etappe 3: Texte und Rechnungen aus dem Admin-Panel (public/admin.js), wortgleich ins Ticketsystem uebernommen
// Etappe 3: Texte und Rechnungen aus dem frueheren Admin-Panel des Portals, wortgleich ins Ticketsystem uebernommen
const fmt = await loadModule('src/lib/format.js')
const credit = await loadModule('src/lib/creditFormat.js')
const offer = await loadModule('src/lib/offerFormat.js')