Reorganize into monorepo layout, move mitarbeiter-app to legacy reference
Consolidates the previously separate omsorgapp and omsorgCore repos (each had their own nested .git with GitHub history) plus the old root-level website/mitarbeiter-app into a single monorepo, matching the structure already documented in the root CLAUDE.md. Also moves the PHP employee app aside as omsorgWeb/mitarbeiter-app-legacy/ to serve as a template for a ground-up rewrite. Fixes .gitignore in the same pass: the config-secrets/uploads/data patterns were unanchored (relative to repo root, not depth-agnostic), so they silently stopped matching once the app moved under omsorgWeb/. Patterns are now **/-prefixed and cover both mitarbeiter-app and mitarbeiter-app-legacy, keeping DB/SMTP credentials and uploaded employee documents out of version control. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
8beb0fcf52
commit
b6c1389c55
@@ -0,0 +1,197 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Pencil } from "lucide-react";
|
||||
|
||||
import OmsorgCard from "../../components/OmsorgCard";
|
||||
import OmsorgBadge from "../../components/ui/OmsorgBadge";
|
||||
import OmsorgButton from "../../components/ui/OmsorgButton";
|
||||
import { useAuth } from "../../app/AuthContext";
|
||||
import EmployeeTabs from "./EmployeeTabs";
|
||||
import EditEmployeeDialog from "./EditEmployeeDialog";
|
||||
|
||||
function getInitials(firstName = "", lastName = "") {
|
||||
return `${firstName[0] ?? ""}${lastName[0] ?? ""}`.toUpperCase();
|
||||
}
|
||||
|
||||
function formatDate(value) {
|
||||
if (!value) return "—";
|
||||
return new Date(value).toLocaleDateString("de-DE");
|
||||
}
|
||||
|
||||
function formatAddress(employee) {
|
||||
const line = [employee.postalCode, employee.city].filter(Boolean).join(" ");
|
||||
const parts = [employee.street, line].filter(Boolean);
|
||||
|
||||
if (employee.country && employee.country !== "Deutschland") {
|
||||
parts.push(employee.country);
|
||||
}
|
||||
|
||||
return parts.length > 0 ? parts.join(", ") : "—";
|
||||
}
|
||||
|
||||
export default function EmployeeDetailPanel({ employee, onUpdated }) {
|
||||
const { hasPermission } = useAuth();
|
||||
const canEdit = hasPermission("Employees", "Edit");
|
||||
const [activeTab, setActiveTab] = useState("overview");
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveTab("overview");
|
||||
}, [employee?.id]);
|
||||
|
||||
if (!employee) {
|
||||
return (
|
||||
<OmsorgCard>
|
||||
<div className="employee-detail-empty">
|
||||
<h2>Keine Personalakte ausgewählt</h2>
|
||||
<p>Wähle links einen Mitarbeiter aus.</p>
|
||||
</div>
|
||||
</OmsorgCard>
|
||||
);
|
||||
}
|
||||
|
||||
const renderTabContent = () => {
|
||||
switch (activeTab) {
|
||||
case "documents":
|
||||
return (
|
||||
<div className="employee-tab-content">
|
||||
<h3>Dokumente</h3>
|
||||
<p>
|
||||
Hier werden später Arbeitsverträge,
|
||||
Nachweise und weitere Dokumente angezeigt.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
case "contracts":
|
||||
return (
|
||||
<div className="employee-tab-content">
|
||||
<h3>Verträge</h3>
|
||||
<p>
|
||||
Hier erscheint später der Arbeitsvertrag
|
||||
mit Beginn, Ende und Konditionen.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
case "qualifications":
|
||||
return (
|
||||
<div className="employee-tab-content">
|
||||
<h3>Qualifikationen</h3>
|
||||
<p>
|
||||
Hier erscheinen später Ausbildung,
|
||||
Zertifikate und Fortbildungen.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
case "assignments":
|
||||
return (
|
||||
<div className="employee-tab-content">
|
||||
<h3>Einsätze</h3>
|
||||
<p>
|
||||
Hier wird später die komplette
|
||||
Einsatzhistorie angezeigt.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
case "overview":
|
||||
default:
|
||||
return (
|
||||
<div className="employee-detail-grid">
|
||||
<div>
|
||||
<strong>Telefon</strong>
|
||||
<p>{employee.phoneNumber ?? "—"}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>E-Mail</strong>
|
||||
<p>{employee.email ?? "—"}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Adresse</strong>
|
||||
<p>{formatAddress(employee)}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Geburtsdatum</strong>
|
||||
<p>{formatDate(employee.dateOfBirth)}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Eintritt</strong>
|
||||
<p>{formatDate(employee.entryDate)}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Austritt</strong>
|
||||
<p>{formatDate(employee.exitDate)}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Beschäftigungsart</strong>
|
||||
<p>{employee.employmentType ?? "—"}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Qualifikation</strong>
|
||||
<p>{employee.qualification ?? "—"}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Notfallkontakt</strong>
|
||||
<p>
|
||||
{employee.emergencyContactName
|
||||
? `${employee.emergencyContactName}${
|
||||
employee.emergencyContactRelation ? ` (${employee.emergencyContactRelation})` : ""
|
||||
}${employee.emergencyContactPhone ? ` — ${employee.emergencyContactPhone}` : ""}`
|
||||
: "—"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<OmsorgCard>
|
||||
<div className="employee-detail">
|
||||
<div className="employee-detail-header">
|
||||
<div className="employee-detail-avatar">
|
||||
{getInitials(employee.firstName, employee.lastName)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>{`${employee.firstName} ${employee.lastName}`.trim()}</h2>
|
||||
<OmsorgBadge status={employee.status?.toLowerCase()} />
|
||||
</div>
|
||||
|
||||
{canEdit && (
|
||||
<OmsorgButton variant="secondary" icon={Pencil} onClick={() => setIsEditDialogOpen(true)}>
|
||||
Bearbeiten
|
||||
</OmsorgButton>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<EmployeeTabs
|
||||
activeTab={activeTab}
|
||||
onChange={setActiveTab}
|
||||
/>
|
||||
|
||||
{renderTabContent()}
|
||||
</div>
|
||||
|
||||
{isEditDialogOpen && (
|
||||
<EditEmployeeDialog
|
||||
employee={employee}
|
||||
onClose={() => setIsEditDialogOpen(false)}
|
||||
onUpdated={(updatedEmployee) => {
|
||||
setIsEditDialogOpen(false);
|
||||
onUpdated?.(updatedEmployee);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</OmsorgCard>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user