Dummydaten und Sprache angepasst
Dieser Commit ist enthalten in:
@ -46,9 +46,9 @@ export default function CreateEmployee() {
|
||||
case 'stellvertreter':
|
||||
return 'Stellvertretung'
|
||||
case 'beauftragter':
|
||||
return 'Beauftragte:r'
|
||||
return 'Beauftragte Person'
|
||||
default:
|
||||
return 'Mitarbeiter:in'
|
||||
return 'Teammitglied'
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,9 +73,9 @@ export default function CreateEmployee() {
|
||||
|
||||
if (response.data.data?.temporaryPassword) {
|
||||
setCreatedUser({ password: response.data.data.temporaryPassword })
|
||||
setSuccess(`Mitarbeiter und Benutzerkonto erfolgreich erstellt!`)
|
||||
setSuccess(`Profil und Benutzerkonto erfolgreich erstellt!`)
|
||||
} else {
|
||||
setSuccess('Mitarbeiter erfolgreich erstellt!')
|
||||
setSuccess('Profil erfolgreich erstellt!')
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Error:', err.response?.data)
|
||||
@ -96,8 +96,8 @@ export default function CreateEmployee() {
|
||||
const getRoleDescription = (role: UserRole): string => {
|
||||
const descriptions = {
|
||||
admin: 'Vollzugriff auf alle Funktionen inklusive Admin Panel und Benutzerverwaltung',
|
||||
superuser: 'Kann Mitarbeiter anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeiter durchsuchen'
|
||||
superuser: 'Kann Mitarbeitende anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeitende durchsuchen'
|
||||
}
|
||||
return descriptions[role]
|
||||
}
|
||||
@ -112,10 +112,10 @@ export default function CreateEmployee() {
|
||||
← Zurück zur Benutzerverwaltung
|
||||
</button>
|
||||
<h1 className="text-title-lg font-poppins font-bold text-primary">
|
||||
Neuen Mitarbeiter & Benutzer anlegen
|
||||
Neues Mitarbeitendenprofil & Benutzer anlegen
|
||||
</h1>
|
||||
<p className="text-body text-secondary mt-2">
|
||||
Erstellen Sie einen neuen Mitarbeiter-Datensatz und optional ein Benutzerkonto
|
||||
Erstellen Sie ein neues Profil und optional ein Benutzerkonto
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -141,7 +141,7 @@ export default function CreateEmployee() {
|
||||
{createdUser.password}
|
||||
</code>
|
||||
<p className="text-sm mt-2 text-green-700">
|
||||
⚠️ Bitte notieren Sie dieses Passwort und geben Sie es sicher an den Mitarbeiter weiter.
|
||||
⚠️ Bitte notieren Sie dieses Passwort und geben Sie es sicher an die betreffende Person weiter.
|
||||
Das Passwort muss beim ersten Login geändert werden.
|
||||
</p>
|
||||
<div className="mt-4 flex justify-end">
|
||||
@ -160,7 +160,7 @@ export default function CreateEmployee() {
|
||||
|
||||
<div className="card mb-6">
|
||||
<h2 className="text-title-card font-poppins font-semibold text-primary mb-6">
|
||||
Mitarbeiter-Grunddaten
|
||||
Grunddaten des Profils
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
@ -251,7 +251,7 @@ export default function CreateEmployee() {
|
||||
}}
|
||||
/>
|
||||
<p className="text-sm text-secondary-light mt-2">
|
||||
Wählen Sie die primäre Organisationseinheit für den neuen Mitarbeiter. Die Abteilung wird automatisch anhand der Auswahl gesetzt.
|
||||
Wählen Sie die primäre Organisationseinheit für die neue Person. Die Abteilung wird automatisch anhand der Auswahl gesetzt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -265,10 +265,10 @@ export default function CreateEmployee() {
|
||||
onChange={event => setSelectedUnitRole(event.target.value as EmployeeUnitRole)}
|
||||
className="input-field w-full"
|
||||
>
|
||||
<option value="leiter">Leiter:in</option>
|
||||
<option value="leiter">Leitung</option>
|
||||
<option value="stellvertreter">Stellvertretung</option>
|
||||
<option value="mitarbeiter">Mitarbeiter:in</option>
|
||||
<option value="beauftragter">Beauftragte:r</option>
|
||||
<option value="mitarbeiter">Teammitglied</option>
|
||||
<option value="beauftragter">Beauftragte Person</option>
|
||||
</select>
|
||||
<p className="text-sm text-secondary-light mt-2">
|
||||
Diese Rolle wird für Vertretungs- und Organigramm-Funktionen verwendet.
|
||||
@ -296,7 +296,7 @@ export default function CreateEmployee() {
|
||||
</span>
|
||||
</label>
|
||||
<p className="text-sm text-secondary-light mt-2 ml-7">
|
||||
Erstellt ein Benutzerkonto, mit dem sich der Mitarbeiter im System anmelden kann.
|
||||
Erstellt ein Benutzerkonto, mit dem sich die angelegte Person im System anmelden kann.
|
||||
Ein sicheres temporäres Passwort wird automatisch generiert.
|
||||
</p>
|
||||
</div>
|
||||
@ -327,10 +327,10 @@ export default function CreateEmployee() {
|
||||
📋 Was passiert als Nächstes?
|
||||
</h3>
|
||||
<ul className="space-y-2 text-body text-secondary">
|
||||
<li>• Der Mitarbeiter wird mit Grunddaten angelegt (Position: "Mitarbeiter", Telefon: "Nicht angegeben")</li>
|
||||
<li>• Die Person wird mit Grunddaten angelegt (Position: "Teammitglied", Telefon: "Nicht angegeben")</li>
|
||||
<li>• {watchCreateUser ? 'Ein Benutzerkonto wird erstellt und ein temporäres Passwort generiert' : 'Kein Benutzerkonto wird erstellt'}</li>
|
||||
<li>• {selectedUnitId ? `Die Organisationseinheit ${selectedUnitName} (${getUnitRoleLabel(selectedUnitRole)}) wird als primäre Zuordnung hinterlegt` : 'Organisationseinheit kann später im Organigramm zugewiesen werden'}</li>
|
||||
<li>• Der Mitarbeiter kann später im Frontend seine Profildaten vervollständigen</li>
|
||||
<li>• Die Person kann später im Frontend das Profil vervollständigen</li>
|
||||
<li>• Alle Daten werden verschlüsselt in der Datenbank gespeichert</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -349,7 +349,7 @@ export default function CreateEmployee() {
|
||||
className="btn-primary"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? 'Erstelle...' : 'Mitarbeiter erstellen'}
|
||||
{loading ? 'Erstelle...' : 'Profil erstellen'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,19 +1,15 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { api } from '../services/api'
|
||||
import SyncStatus from '../components/SyncStatus'
|
||||
|
||||
interface DashboardStats {
|
||||
totalEmployees: number
|
||||
totalSkills: number
|
||||
totalUsers: number
|
||||
lastSync?: {
|
||||
timestamp: string
|
||||
success: boolean
|
||||
itemsSynced: number
|
||||
}
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
const navigate = useNavigate()
|
||||
const [stats, setStats] = useState<DashboardStats>({
|
||||
totalEmployees: 0,
|
||||
totalSkills: 0,
|
||||
@ -65,23 +61,19 @@ export default function Dashboard() {
|
||||
|
||||
const statsCards = [
|
||||
{
|
||||
title: 'Mitarbeiter',
|
||||
title: 'Mitarbeitende',
|
||||
value: stats.totalEmployees,
|
||||
color: 'text-primary-blue',
|
||||
bgColor: 'bg-bg-accent',
|
||||
path: '/users'
|
||||
},
|
||||
{
|
||||
title: 'Skills',
|
||||
value: stats.totalSkills,
|
||||
color: 'text-success',
|
||||
bgColor: 'bg-success-bg',
|
||||
},
|
||||
{
|
||||
title: 'Benutzer',
|
||||
value: stats.totalUsers,
|
||||
color: 'text-info',
|
||||
bgColor: 'bg-info-bg',
|
||||
},
|
||||
path: '/skills'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
@ -90,9 +82,14 @@ export default function Dashboard() {
|
||||
Dashboard
|
||||
</h1>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||
{statsCards.map((stat, index) => (
|
||||
<div key={index} className="card">
|
||||
<button
|
||||
key={index}
|
||||
type="button"
|
||||
onClick={() => navigate(stat.path)}
|
||||
className="card text-left transition hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-primary-blue"
|
||||
>
|
||||
<div className={`w-16 h-16 rounded-card ${stat.bgColor} flex items-center justify-center mb-4`}>
|
||||
<span className={`text-2xl font-bold ${stat.color}`}>
|
||||
{stat.value}
|
||||
@ -101,60 +98,11 @@ export default function Dashboard() {
|
||||
<h3 className="text-body font-medium text-tertiary">
|
||||
{stat.title}
|
||||
</h3>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<div className="card">
|
||||
<h2 className="text-title-card font-poppins font-semibold text-primary mb-4">
|
||||
Letzte Synchronisation
|
||||
</h2>
|
||||
{stats.lastSync ? (
|
||||
<div className="space-y-2">
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Zeitpunkt:</span>{' '}
|
||||
{new Date(stats.lastSync.timestamp).toLocaleString('de-DE')}
|
||||
</p>
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Status:</span>{' '}
|
||||
<span className={stats.lastSync.success ? 'text-success' : 'text-error'}>
|
||||
{stats.lastSync.success ? 'Erfolgreich' : 'Fehlgeschlagen'}
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Synchronisierte Elemente:</span>{' '}
|
||||
{stats.lastSync.itemsSynced}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-body text-tertiary">
|
||||
Noch keine Synchronisation durchgeführt
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card">
|
||||
<h2 className="text-title-card font-poppins font-semibold text-primary mb-4">
|
||||
Systemstatus
|
||||
</h2>
|
||||
<div className="space-y-2">
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Backend:</span>{' '}
|
||||
<span className="text-success">Online</span>
|
||||
</p>
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Datenbank:</span>{' '}
|
||||
<span className="text-success">Verbunden</span>
|
||||
</p>
|
||||
<p className="text-body text-secondary">
|
||||
<span className="font-medium">Version:</span> 1.0.0
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SyncStatus />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ export default function EmployeeForm() {
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch employee:', error)
|
||||
setError('Mitarbeiter konnte nicht geladen werden')
|
||||
setError('Profil konnte nicht geladen werden')
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +80,8 @@ export default function EmployeeForm() {
|
||||
const getRoleDescription = (role: UserRole): string => {
|
||||
const descriptions = {
|
||||
admin: 'Vollzugriff auf alle Funktionen inklusive Admin Panel und Benutzerverwaltung',
|
||||
superuser: 'Kann Mitarbeiter anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeiter durchsuchen'
|
||||
superuser: 'Kann Mitarbeitende anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeitende durchsuchen'
|
||||
}
|
||||
return descriptions[role]
|
||||
}
|
||||
@ -96,7 +96,7 @@ export default function EmployeeForm() {
|
||||
← Zurück zur Übersicht
|
||||
</button>
|
||||
<h1 className="text-title-lg font-poppins font-bold text-primary">
|
||||
{isEdit ? 'Mitarbeiter bearbeiten' : 'Neuer Mitarbeiter'}
|
||||
{isEdit ? 'Mitarbeitendenprofil bearbeiten' : 'Neues Mitarbeitendenprofil'}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@ -109,7 +109,7 @@ export default function EmployeeForm() {
|
||||
|
||||
<div className="card mb-6">
|
||||
<h2 className="text-title-card font-poppins font-semibold text-primary mb-6">
|
||||
Mitarbeiterdaten
|
||||
Profilinformationen
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
@ -192,7 +192,7 @@ export default function EmployeeForm() {
|
||||
className="w-5 h-5 rounded border-border-input text-primary-blue focus:ring-primary-blue"
|
||||
/>
|
||||
<span className="text-body text-secondary">
|
||||
Benutzerkonto für diesen Mitarbeiter erstellen
|
||||
Benutzerkonto für diese Person erstellen
|
||||
</span>
|
||||
</label>
|
||||
<p className="text-small text-tertiary mt-1">
|
||||
@ -242,10 +242,10 @@ export default function EmployeeForm() {
|
||||
disabled={loading}
|
||||
className="btn-primary disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{loading ? 'Speichern...' : (isEdit ? 'Änderungen speichern' : 'Mitarbeiter anlegen')}
|
||||
{loading ? 'Speichern...' : (isEdit ? 'Änderungen speichern' : 'Profil anlegen')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ export default function EmployeeFormComplete() {
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch employee:', error)
|
||||
setError('Mitarbeiter konnte nicht geladen werden')
|
||||
setError('Profil konnte nicht geladen werden')
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,15 +97,15 @@ export default function EmployeeFormComplete() {
|
||||
let response
|
||||
if (isEdit) {
|
||||
response = await api.put(`/employees/${id}`, payload)
|
||||
setSuccess('Mitarbeiter erfolgreich aktualisiert!')
|
||||
setSuccess('Profil erfolgreich aktualisiert!')
|
||||
} else {
|
||||
response = await api.post('/employees', payload)
|
||||
|
||||
if (response.data.data.temporaryPassword) {
|
||||
setCreatedUser({ password: response.data.data.temporaryPassword })
|
||||
setSuccess(`Mitarbeiter erfolgreich erstellt! Temporäres Passwort: ${response.data.data.temporaryPassword}`)
|
||||
setSuccess(`Profil erfolgreich erstellt! Temporäres Passwort: ${response.data.data.temporaryPassword}`)
|
||||
} else {
|
||||
setSuccess('Mitarbeiter erfolgreich erstellt!')
|
||||
setSuccess('Profil erfolgreich erstellt!')
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,8 +131,8 @@ export default function EmployeeFormComplete() {
|
||||
const getRoleDescription = (role: UserRole): string => {
|
||||
const descriptions = {
|
||||
admin: 'Vollzugriff auf alle Funktionen inklusive Admin Panel und Benutzerverwaltung',
|
||||
superuser: 'Kann Mitarbeiter anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeiter durchsuchen'
|
||||
superuser: 'Kann Mitarbeitende anlegen und verwalten, aber kein Zugriff auf Admin Panel',
|
||||
user: 'Kann nur das eigene Profil bearbeiten und Mitarbeitende durchsuchen'
|
||||
}
|
||||
return descriptions[role]
|
||||
}
|
||||
@ -147,7 +147,7 @@ export default function EmployeeFormComplete() {
|
||||
← Zurück zur Übersicht
|
||||
</button>
|
||||
<h1 className="text-title-lg font-poppins font-bold text-primary">
|
||||
{isEdit ? 'Mitarbeiter bearbeiten' : 'Neuer Mitarbeiter'}
|
||||
{isEdit ? 'Mitarbeitendenprofil bearbeiten' : 'Neues Mitarbeitendenprofil'}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@ -207,10 +207,10 @@ export default function EmployeeFormComplete() {
|
||||
|
||||
<div>
|
||||
<label className="block text-body font-medium text-secondary mb-2">
|
||||
Mitarbeiternummer *
|
||||
Personalnummer *
|
||||
</label>
|
||||
<input
|
||||
{...register('employeeNumber', { required: 'Mitarbeiternummer ist erforderlich' })}
|
||||
{...register('employeeNumber', { required: 'Personalnummer ist erforderlich' })}
|
||||
className="input-field w-full"
|
||||
placeholder="EMP001"
|
||||
/>
|
||||
@ -346,7 +346,7 @@ export default function EmployeeFormComplete() {
|
||||
className="w-5 h-5 rounded border-border-input text-primary-blue focus:ring-primary-blue"
|
||||
/>
|
||||
<span className="text-body font-medium text-secondary">
|
||||
Benutzerkonto für diesen Mitarbeiter erstellen
|
||||
Benutzerkonto für diese Person erstellen
|
||||
</span>
|
||||
</label>
|
||||
<p className="text-sm text-secondary-light mt-1 ml-7">
|
||||
@ -395,4 +395,4 @@ export default function EmployeeFormComplete() {
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ export default function EmployeeManagement() {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-tertiary">Mitarbeiter werden geladen...</p>
|
||||
<p className="text-tertiary">Mitarbeitende werden geladen...</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -42,13 +42,13 @@ export default function EmployeeManagement() {
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<h1 className="text-title-lg font-poppins font-bold text-primary">
|
||||
Mitarbeiterverwaltung
|
||||
Mitarbeitendenverwaltung
|
||||
</h1>
|
||||
<button
|
||||
onClick={() => navigate('/employees/new')}
|
||||
className="btn-primary"
|
||||
>
|
||||
Neuer Mitarbeiter
|
||||
Neues Mitarbeitendenprofil
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -110,10 +110,10 @@ export default function EmployeeManagement() {
|
||||
|
||||
{filteredEmployees.length === 0 && (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-tertiary">Keine Mitarbeiter gefunden</p>
|
||||
<p className="text-tertiary">Keine Mitarbeitenden gefunden</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ const OrganizationNode = ({ data }: { data: any }) => {
|
||||
</h4>
|
||||
{data.employeeCount !== undefined && (
|
||||
<p className="text-[11px] text-slate-600 mt-1">
|
||||
👥 {data.employeeCount} Mitarbeiter
|
||||
👥 {data.employeeCount} Mitarbeitende
|
||||
</p>
|
||||
)}
|
||||
{data.hasFuehrungsstelle && (
|
||||
|
||||
@ -454,7 +454,7 @@ export default function SyncSettings() {
|
||||
checked={syncSettings.syncEmployees}
|
||||
onChange={(e) => setSyncSettings({ ...syncSettings, syncEmployees: e.target.checked })}
|
||||
/>
|
||||
<span className="text-sm">Mitarbeiterdaten</span>
|
||||
<span className="text-sm">Daten der Mitarbeitenden</span>
|
||||
</label>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
@ -514,4 +514,4 @@ export default function SyncSettings() {
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ export default function UserManagement() {
|
||||
onClick={() => navigate('/users/create-employee')}
|
||||
className="btn-primary"
|
||||
>
|
||||
+ Neuen Mitarbeiter anlegen
|
||||
+ Neues Mitarbeitendenprofil anlegen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -303,7 +303,7 @@ export default function UserManagement() {
|
||||
Benutzer
|
||||
</th>
|
||||
<th className="text-left py-3 px-4 font-poppins font-medium text-secondary">
|
||||
Mitarbeiter
|
||||
Mitarbeitende
|
||||
</th>
|
||||
<th className="text-left py-3 px-4 font-poppins font-medium text-secondary">
|
||||
Rolle
|
||||
@ -483,9 +483,9 @@ export default function UserManagement() {
|
||||
</h3>
|
||||
<ul className="space-y-2 text-body text-secondary">
|
||||
<li>• <strong>Administrator:</strong> Vollzugriff auf alle Funktionen und Einstellungen</li>
|
||||
<li>• <strong>Poweruser:</strong> Kann Mitarbeiter und Skills verwalten, aber keine Systemeinstellungen ändern</li>
|
||||
<li>• <strong>Poweruser:</strong> Kann Mitarbeitende und Skills verwalten, aber keine Systemeinstellungen ändern</li>
|
||||
<li>• <strong>Benutzer:</strong> Kann nur eigenes Profil bearbeiten und Daten einsehen</li>
|
||||
<li>• Neue Benutzer können über den Import oder die Mitarbeiterverwaltung angelegt werden</li>
|
||||
<li>• Neue Benutzer können über den Import oder die Mitarbeitendenverwaltung angelegt werden</li>
|
||||
<li>• Der Admin-Benutzer kann nicht gelöscht werden</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren