mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 15:05:45 +01:00
changed static password length statements 6 -> 8
This commit is contained in:
@@ -766,7 +766,7 @@ export const changePassword = async (req: AuthRequest, res: Response): Promise<v
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate new password
|
// Validate new password
|
||||||
if (!newPassword || newPassword.length < 6) {
|
if (!newPassword || newPassword.length < 8) {
|
||||||
res.status(400).json({ error: 'New password must be at least 8 characters long' });
|
res.status(400).json({ error: 'New password must be at least 8 characters long' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function generateEmail(firstname: string, lastname: string): string {
|
|||||||
|
|
||||||
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
||||||
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
||||||
|
|
||||||
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,15 +31,15 @@ export const checkSetupStatus = async (req: Request, res: Response): Promise<voi
|
|||||||
);
|
);
|
||||||
|
|
||||||
console.log('Admin exists check:', adminExists);
|
console.log('Admin exists check:', adminExists);
|
||||||
|
|
||||||
const needsSetup = !adminExists || adminExists['COUNT(*)'] === 0;
|
const needsSetup = !adminExists || adminExists['COUNT(*)'] === 0;
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
needsSetup: needsSetup
|
needsSetup: needsSetup
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking setup status:', error);
|
console.error('Error checking setup status:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: 'Internal server error during setup check'
|
error: 'Internal server error during setup check'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,8 @@ export const setupAdmin = async (req: Request, res: Response): Promise<void> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Password length validation
|
// Password length validation
|
||||||
if (password.length < 6) {
|
if (password.length < 8) {
|
||||||
res.status(400).json({ error: 'Das Passwort muss mindestens 6 Zeichen lang sein' });
|
res.status(400).json({ error: 'Das Passwort muss mindestens 8 Zeichen lang sein' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,15 +125,15 @@ export const setupAdmin = async (req: Request, res: Response): Promise<void> =>
|
|||||||
} catch (dbError) {
|
} catch (dbError) {
|
||||||
await db.run('ROLLBACK');
|
await db.run('ROLLBACK');
|
||||||
console.error('❌ Database error during admin creation:', dbError);
|
console.error('❌ Database error during admin creation:', dbError);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: 'Fehler beim Erstellen des Admin-Accounts'
|
error: 'Fehler beim Erstellen des Admin-Accounts'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error in setup:', error);
|
console.error('❌ Error in setup:', error);
|
||||||
|
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: 'Ein unerwarteter Fehler ist aufgetreten'
|
error: 'Ein unerwarteter Fehler ist aufgetreten'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
### \[CREATE\] Employee
|
### \[CREATE\] Employee
|
||||||
* `firstname` 1-100 characters and must not be empty
|
* `firstname` 1-100 characters and must not be empty
|
||||||
* `lastname` 1-100 characters and must not be empty
|
* `lastname` 1-100 characters and must not be empty
|
||||||
* `password` must be at least 6 characters (in create mode)
|
* `password` must be at least 8 characters (in create mode)
|
||||||
* `employeeType` must be `manager`, `personell`, `apprentice`, or `guest`
|
* `employeeType` must be `manager`, `personell`, `apprentice`, or `guest`
|
||||||
* `canWorkAlone` optional boolean
|
* `canWorkAlone` optional boolean
|
||||||
* `isTrainee` optional boolean
|
* `isTrainee` optional boolean
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ function generateEmail(firstname: string, lastname: string): string {
|
|||||||
|
|
||||||
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
||||||
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
||||||
|
|
||||||
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@ function generateEmail(firstname: string, lastname: string): string {
|
|||||||
export function validateEmployeeData(employee: CreateEmployeeRequest): string[] {
|
export function validateEmployeeData(employee: CreateEmployeeRequest): string[] {
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
if (employee.password?.length < 6) {
|
if (employee.password?.length < 8) {
|
||||||
errors.push('Password must be at least 6 characters long');
|
errors.push('Password must be at least 8 characters long');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!employee.firstname?.trim() || employee.firstname.trim().length < 2) {
|
if (!employee.firstname?.trim() || employee.firstname.trim().length < 2) {
|
||||||
@@ -72,16 +72,16 @@ export function generateEmployeeEmail(firstname: string, lastname: string): stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UPDATED: Business logic helpers for new employee types
|
// UPDATED: Business logic helpers for new employee types
|
||||||
export const isManager = (employee: Employee): boolean =>
|
export const isManager = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'manager';
|
employee.employeeType === 'manager';
|
||||||
|
|
||||||
export const isPersonell = (employee: Employee): boolean =>
|
export const isPersonell = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell';
|
employee.employeeType === 'personell';
|
||||||
|
|
||||||
export const isApprentice = (employee: Employee): boolean =>
|
export const isApprentice = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'apprentice';
|
employee.employeeType === 'apprentice';
|
||||||
|
|
||||||
export const isGuest = (employee: Employee): boolean =>
|
export const isGuest = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'guest';
|
employee.employeeType === 'guest';
|
||||||
|
|
||||||
export const isInternal = (employee: Employee): boolean =>
|
export const isInternal = (employee: Employee): boolean =>
|
||||||
@@ -91,24 +91,24 @@ export const isExternal = (employee: Employee): boolean =>
|
|||||||
employee.employeeType === 'guest';
|
employee.employeeType === 'guest';
|
||||||
|
|
||||||
// UPDATED: Trainee logic - now based on isTrainee field for personell type
|
// UPDATED: Trainee logic - now based on isTrainee field for personell type
|
||||||
export const isTrainee = (employee: Employee): boolean =>
|
export const isTrainee = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell' && employee.isTrainee;
|
employee.employeeType === 'personell' && employee.isTrainee;
|
||||||
|
|
||||||
export const isExperienced = (employee: Employee): boolean =>
|
export const isExperienced = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell' && !employee.isTrainee;
|
employee.employeeType === 'personell' && !employee.isTrainee;
|
||||||
|
|
||||||
// Role-based helpers
|
// Role-based helpers
|
||||||
export const isAdmin = (employee: Employee): boolean =>
|
export const isAdmin = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('admin') || false;
|
employee.roles?.includes('admin') || false;
|
||||||
|
|
||||||
export const isMaintenance = (employee: Employee): boolean =>
|
export const isMaintenance = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('maintenance') || false;
|
employee.roles?.includes('maintenance') || false;
|
||||||
|
|
||||||
export const isUser = (employee: Employee): boolean =>
|
export const isUser = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('user') || false;
|
employee.roles?.includes('user') || false;
|
||||||
|
|
||||||
// UPDATED: Work alone permission - managers and experienced personell can work alone
|
// UPDATED: Work alone permission - managers and experienced personell can work alone
|
||||||
export const canEmployeeWorkAlone = (employee: Employee): boolean =>
|
export const canEmployeeWorkAlone = (employee: Employee): boolean =>
|
||||||
employee.canWorkAlone && (isManager(employee) || isExperienced(employee));
|
employee.canWorkAlone && (isManager(employee) || isExperienced(employee));
|
||||||
|
|
||||||
// Helper for full name display
|
// Helper for full name display
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ function generateEmail(firstname: string, lastname: string): string {
|
|||||||
|
|
||||||
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
const cleanFirstname = convertUmlauts(firstname).replace(/[^a-z0-9]/g, '');
|
||||||
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
const cleanLastname = convertUmlauts(lastname).replace(/[^a-z0-9]/g, '');
|
||||||
|
|
||||||
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@ function generateEmail(firstname: string, lastname: string): string {
|
|||||||
export function validateEmployeeData(employee: CreateEmployeeRequest): string[] {
|
export function validateEmployeeData(employee: CreateEmployeeRequest): string[] {
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
if (employee.password?.length < 6) {
|
if (employee.password?.length < 8) {
|
||||||
errors.push('Password must be at least 6 characters long');
|
errors.push('Password must be at least 8 characters long');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!employee.firstname?.trim() || employee.firstname.trim().length < 2) {
|
if (!employee.firstname?.trim() || employee.firstname.trim().length < 2) {
|
||||||
@@ -72,16 +72,16 @@ export function generateEmployeeEmail(firstname: string, lastname: string): stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UPDATED: Business logic helpers for new employee types
|
// UPDATED: Business logic helpers for new employee types
|
||||||
export const isManager = (employee: Employee): boolean =>
|
export const isManager = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'manager';
|
employee.employeeType === 'manager';
|
||||||
|
|
||||||
export const isPersonell = (employee: Employee): boolean =>
|
export const isPersonell = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell';
|
employee.employeeType === 'personell';
|
||||||
|
|
||||||
export const isApprentice = (employee: Employee): boolean =>
|
export const isApprentice = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'apprentice';
|
employee.employeeType === 'apprentice';
|
||||||
|
|
||||||
export const isGuest = (employee: Employee): boolean =>
|
export const isGuest = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'guest';
|
employee.employeeType === 'guest';
|
||||||
|
|
||||||
export const isInternal = (employee: Employee): boolean =>
|
export const isInternal = (employee: Employee): boolean =>
|
||||||
@@ -91,24 +91,24 @@ export const isExternal = (employee: Employee): boolean =>
|
|||||||
employee.employeeType === 'guest';
|
employee.employeeType === 'guest';
|
||||||
|
|
||||||
// UPDATED: Trainee logic - now based on isTrainee field for personell type
|
// UPDATED: Trainee logic - now based on isTrainee field for personell type
|
||||||
export const isTrainee = (employee: Employee): boolean =>
|
export const isTrainee = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell' && employee.isTrainee;
|
employee.employeeType === 'personell' && employee.isTrainee;
|
||||||
|
|
||||||
export const isExperienced = (employee: Employee): boolean =>
|
export const isExperienced = (employee: Employee): boolean =>
|
||||||
employee.employeeType === 'personell' && !employee.isTrainee;
|
employee.employeeType === 'personell' && !employee.isTrainee;
|
||||||
|
|
||||||
// Role-based helpers
|
// Role-based helpers
|
||||||
export const isAdmin = (employee: Employee): boolean =>
|
export const isAdmin = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('admin') || false;
|
employee.roles?.includes('admin') || false;
|
||||||
|
|
||||||
export const isMaintenance = (employee: Employee): boolean =>
|
export const isMaintenance = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('maintenance') || false;
|
employee.roles?.includes('maintenance') || false;
|
||||||
|
|
||||||
export const isUser = (employee: Employee): boolean =>
|
export const isUser = (employee: Employee): boolean =>
|
||||||
employee.roles?.includes('user') || false;
|
employee.roles?.includes('user') || false;
|
||||||
|
|
||||||
// UPDATED: Work alone permission - managers and experienced personell can work alone
|
// UPDATED: Work alone permission - managers and experienced personell can work alone
|
||||||
export const canEmployeeWorkAlone = (employee: Employee): boolean =>
|
export const canEmployeeWorkAlone = (employee: Employee): boolean =>
|
||||||
employee.canWorkAlone && (isManager(employee) || isExperienced(employee));
|
employee.canWorkAlone && (isManager(employee) || isExperienced(employee));
|
||||||
|
|
||||||
// Helper for full name display
|
// Helper for full name display
|
||||||
|
|||||||
@@ -203,11 +203,11 @@ const Settings: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passwordForm.newPassword.length < 6) {
|
if (passwordForm.newPassword.length < 8) {
|
||||||
showNotification({
|
showNotification({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: 'Fehler',
|
title: 'Fehler',
|
||||||
message: 'Das neue Passwort muss mindestens 6 Zeichen lang sein'
|
message: 'Das neue Passwort muss mindestens 8 Zeichen lang sein'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -600,9 +600,9 @@ const Settings: React.FC = () => {
|
|||||||
value={passwordForm.newPassword}
|
value={passwordForm.newPassword}
|
||||||
onChange={handlePasswordChange}
|
onChange={handlePasswordChange}
|
||||||
required
|
required
|
||||||
minLength={6}
|
minLength={8}
|
||||||
style={styles.fieldInputWithIcon}
|
style={styles.fieldInputWithIcon}
|
||||||
placeholder="Mindestens 6 Zeichen"
|
placeholder="Mindestens 8 Zeichen"
|
||||||
onFocus={(e) => {
|
onFocus={(e) => {
|
||||||
e.target.style.borderColor = '#1a1325';
|
e.target.style.borderColor = '#1a1325';
|
||||||
e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)';
|
e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)';
|
||||||
@@ -631,7 +631,7 @@ const Settings: React.FC = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={styles.fieldHint}>
|
<div style={styles.fieldHint}>
|
||||||
Das Passwort muss mindestens 6 Zeichen lang sein.
|
Das Passwort muss mindestens 8 Zeichen lang sein.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const useSetup = () => {
|
|||||||
|
|
||||||
const steps: SetupStep[] = [
|
const steps: SetupStep[] = [
|
||||||
{
|
{
|
||||||
id: 'profile-setup',
|
id: 'profile-setup',
|
||||||
title: 'Profilinformationen',
|
title: 'Profilinformationen',
|
||||||
subtitle: 'Geben Sie Ihre persönlichen Daten ein'
|
subtitle: 'Geben Sie Ihre persönlichen Daten ein'
|
||||||
},
|
},
|
||||||
@@ -62,8 +62,8 @@ const useSetup = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const validateStep2 = (): boolean => {
|
const validateStep2 = (): boolean => {
|
||||||
if (formData.password.length < 6) {
|
if (formData.password.length < 8) {
|
||||||
setError('Das Passwort muss mindestens 6 Zeichen lang sein.');
|
setError('Das Passwort muss mindestens 8 Zeichen lang sein.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (formData.password !== formData.confirmPassword) {
|
if (formData.password !== formData.confirmPassword) {
|
||||||
@@ -87,7 +87,7 @@ const useSetup = () => {
|
|||||||
// ===== NAVIGATIONS-FUNKTIONEN =====
|
// ===== NAVIGATIONS-FUNKTIONEN =====
|
||||||
const goToNextStep = async (): Promise<void> => {
|
const goToNextStep = async (): Promise<void> => {
|
||||||
setError('');
|
setError('');
|
||||||
|
|
||||||
if (!validateCurrentStep(currentStep)) {
|
if (!validateCurrentStep(currentStep)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ const useSetup = () => {
|
|||||||
|
|
||||||
const handleStepChange = (stepIndex: number): void => {
|
const handleStepChange = (stepIndex: number): void => {
|
||||||
setError('');
|
setError('');
|
||||||
|
|
||||||
// Nur erlauben, zu bereits validierten Schritten zu springen
|
// Nur erlauben, zu bereits validierten Schritten zu springen
|
||||||
// oder zum nächsten Schritt nach dem aktuellen
|
// oder zum nächsten Schritt nach dem aktuellen
|
||||||
if (stepIndex <= currentStep + 1) {
|
if (stepIndex <= currentStep + 1) {
|
||||||
@@ -163,7 +163,7 @@ const useSetup = () => {
|
|||||||
|
|
||||||
// Setup Status neu prüfen
|
// Setup Status neu prüfen
|
||||||
await checkSetupStatus();
|
await checkSetupStatus();
|
||||||
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('❌ Setup error:', err);
|
console.error('❌ Setup error:', err);
|
||||||
setError(err.message || 'Ein unerwarteter Fehler ist aufgetreten');
|
setError(err.message || 'Ein unerwarteter Fehler ist aufgetreten');
|
||||||
@@ -177,7 +177,7 @@ const useSetup = () => {
|
|||||||
if (!formData.firstname.trim() || !formData.lastname.trim()) {
|
if (!formData.firstname.trim() || !formData.lastname.trim()) {
|
||||||
return 'vorname.nachname@sp.de';
|
return 'vorname.nachname@sp.de';
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanFirstname = formData.firstname.toLowerCase().replace(/[^a-z0-9]/g, '');
|
const cleanFirstname = formData.firstname.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
const cleanLastname = formData.lastname.toLowerCase().replace(/[^a-z0-9]/g, '');
|
const cleanLastname = formData.lastname.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
return `${cleanFirstname}.${cleanLastname}@sp.de`;
|
||||||
@@ -186,8 +186,8 @@ const useSetup = () => {
|
|||||||
const isStepCompleted = (stepIndex: number): boolean => {
|
const isStepCompleted = (stepIndex: number): boolean => {
|
||||||
switch (stepIndex) {
|
switch (stepIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
return formData.password.length >= 6 &&
|
return formData.password.length >= 8 &&
|
||||||
formData.password === formData.confirmPassword;
|
formData.password === formData.confirmPassword;
|
||||||
case 1:
|
case 1:
|
||||||
return !!formData.firstname.trim() && !!formData.lastname.trim();
|
return !!formData.firstname.trim() && !!formData.lastname.trim();
|
||||||
default:
|
default:
|
||||||
@@ -202,13 +202,13 @@ const useSetup = () => {
|
|||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
steps,
|
steps,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
goToNextStep,
|
goToNextStep,
|
||||||
goToPrevStep,
|
goToPrevStep,
|
||||||
handleStepChange,
|
handleStepChange,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
getEmailPreview,
|
getEmailPreview,
|
||||||
isStepCompleted
|
isStepCompleted
|
||||||
@@ -223,16 +223,16 @@ interface StepContentProps {
|
|||||||
currentStep: number;
|
currentStep: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Step1Content: React.FC<StepContentProps> = ({
|
const Step1Content: React.FC<StepContentProps> = ({
|
||||||
formData,
|
formData,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
getEmailPreview
|
getEmailPreview
|
||||||
}) => (
|
}) => (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
||||||
<div>
|
<div>
|
||||||
<label style={{
|
<label style={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#495057'
|
color: '#495057'
|
||||||
}}>
|
}}>
|
||||||
@@ -257,9 +257,9 @@ const Step1Content: React.FC<StepContentProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style={{
|
<label style={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#495057'
|
color: '#495057'
|
||||||
}}>
|
}}>
|
||||||
@@ -284,17 +284,17 @@ const Step1Content: React.FC<StepContentProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style={{
|
<label style={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#495057'
|
color: '#495057'
|
||||||
}}>
|
}}>
|
||||||
Automatisch generierte E-Mail
|
Automatisch generierte E-Mail
|
||||||
</label>
|
</label>
|
||||||
<div style={{
|
<div style={{
|
||||||
padding: '0.75rem',
|
padding: '0.75rem',
|
||||||
backgroundColor: '#e9ecef',
|
backgroundColor: '#e9ecef',
|
||||||
border: '1px solid #ced4da',
|
border: '1px solid #ced4da',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
color: '#495057',
|
color: '#495057',
|
||||||
@@ -303,8 +303,8 @@ const Step1Content: React.FC<StepContentProps> = ({
|
|||||||
}}>
|
}}>
|
||||||
{getEmailPreview()}
|
{getEmailPreview()}
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
fontSize: '0.875rem',
|
fontSize: '0.875rem',
|
||||||
color: '#6c757d',
|
color: '#6c757d',
|
||||||
marginTop: '0.25rem'
|
marginTop: '0.25rem'
|
||||||
}}>
|
}}>
|
||||||
@@ -315,15 +315,15 @@ const Step1Content: React.FC<StepContentProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const Step2Content: React.FC<StepContentProps> = ({
|
const Step2Content: React.FC<StepContentProps> = ({
|
||||||
formData,
|
formData,
|
||||||
onInputChange
|
onInputChange
|
||||||
}) => (
|
}) => (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
||||||
<div>
|
<div>
|
||||||
<label style={{
|
<label style={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#495057'
|
color: '#495057'
|
||||||
}}>
|
}}>
|
||||||
@@ -342,16 +342,16 @@ const Step2Content: React.FC<StepContentProps> = ({
|
|||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
transition: 'border-color 0.3s ease'
|
transition: 'border-color 0.3s ease'
|
||||||
}}
|
}}
|
||||||
placeholder="Mindestens 6 Zeichen"
|
placeholder="Mindestens 8 Zeichen"
|
||||||
required
|
required
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style={{
|
<label style={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#495057'
|
color: '#495057'
|
||||||
}}>
|
}}>
|
||||||
@@ -378,26 +378,26 @@ const Step2Content: React.FC<StepContentProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Step3Content: React.FC<StepContentProps> = ({
|
const Step3Content: React.FC<StepContentProps> = ({
|
||||||
formData,
|
formData,
|
||||||
getEmailPreview
|
getEmailPreview
|
||||||
}) => (
|
}) => (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
backgroundColor: '#f8f9fa',
|
backgroundColor: '#f8f9fa',
|
||||||
padding: '1.5rem',
|
padding: '1.5rem',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
border: '1px solid #e9ecef'
|
border: '1px solid #e9ecef'
|
||||||
}}>
|
}}>
|
||||||
<h3 style={{
|
<h3 style={{
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
color: '#2c3e50',
|
color: '#2c3e50',
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
fontWeight: '600'
|
fontWeight: '600'
|
||||||
}}>
|
}}>
|
||||||
Zusammenfassung
|
Zusammenfassung
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<span style={{ color: '#6c757d' }}>E-Mail:</span>
|
<span style={{ color: '#6c757d' }}>E-Mail:</span>
|
||||||
@@ -413,15 +413,15 @@ const Step3Content: React.FC<StepContentProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{
|
<div style={{
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
backgroundColor: '#e7f3ff',
|
backgroundColor: '#e7f3ff',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
border: '1px solid #b6d7e8',
|
border: '1px solid #b6d7e8',
|
||||||
color: '#2c3e50'
|
color: '#2c3e50'
|
||||||
}}>
|
}}>
|
||||||
<strong>💡 Wichtig:</strong> Nach dem Setup können Sie sich mit Ihrer
|
<strong>💡 Wichtig:</strong> Nach dem Setup können Sie sich mit Ihrer
|
||||||
automatisch generierten E-Mail anmelden.
|
automatisch generierten E-Mail anmelden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -464,7 +464,7 @@ const Setup: React.FC = () => {
|
|||||||
|
|
||||||
const getNextButtonText = (): string => {
|
const getNextButtonText = (): string => {
|
||||||
if (loading) return '⏳ Wird verarbeitet...';
|
if (loading) return '⏳ Wird verarbeitet...';
|
||||||
|
|
||||||
switch (currentStep) {
|
switch (currentStep) {
|
||||||
case 0:
|
case 0:
|
||||||
return 'Weiter →';
|
return 'Weiter →';
|
||||||
@@ -479,9 +479,9 @@ const Setup: React.FC = () => {
|
|||||||
|
|
||||||
// Inline Step Indicator Komponente
|
// Inline Step Indicator Komponente
|
||||||
const StepIndicator: React.FC = () => (
|
const StepIndicator: React.FC = () => (
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: '2.5rem',
|
marginBottom: '2.5rem',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -497,18 +497,18 @@ const Setup: React.FC = () => {
|
|||||||
backgroundColor: '#e9ecef',
|
backgroundColor: '#e9ecef',
|
||||||
zIndex: 1
|
zIndex: 1
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
{steps.map((step, index) => {
|
{steps.map((step, index) => {
|
||||||
const isCompleted = index < currentStep;
|
const isCompleted = index < currentStep;
|
||||||
const isCurrent = index === currentStep;
|
const isCurrent = index === currentStep;
|
||||||
const isClickable = index <= currentStep + 1;
|
const isClickable = index <= currentStep + 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={step.id}
|
key={step.id}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -538,10 +538,10 @@ const Setup: React.FC = () => {
|
|||||||
>
|
>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
fontWeight: isCurrent ? '600' : '400',
|
fontWeight: isCurrent ? '600' : '400',
|
||||||
color: isCurrent ? '#51258f' : '#6c757d'
|
color: isCurrent ? '#51258f' : '#6c757d'
|
||||||
}}>
|
}}>
|
||||||
@@ -555,8 +555,8 @@ const Setup: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
minHeight: '100vh',
|
minHeight: '100vh',
|
||||||
backgroundColor: '#f8f9fa',
|
backgroundColor: '#f8f9fa',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -573,15 +573,15 @@ const Setup: React.FC = () => {
|
|||||||
border: '1px solid #e9ecef'
|
border: '1px solid #e9ecef'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ textAlign: 'center', marginBottom: '1rem' }}>
|
<div style={{ textAlign: 'center', marginBottom: '1rem' }}>
|
||||||
<h1 style={{
|
<h1 style={{
|
||||||
fontSize: '2rem',
|
fontSize: '2rem',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
color: '#2c3e50'
|
color: '#2c3e50'
|
||||||
}}>
|
}}>
|
||||||
🚀 Erstkonfiguration
|
🚀 Erstkonfiguration
|
||||||
</h1>
|
</h1>
|
||||||
<p style={{
|
<p style={{
|
||||||
color: '#6c757d',
|
color: '#6c757d',
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
marginBottom: '2rem'
|
marginBottom: '2rem'
|
||||||
@@ -592,16 +592,16 @@ const Setup: React.FC = () => {
|
|||||||
|
|
||||||
{/* Aktueller Schritt Titel und Beschreibung */}
|
{/* Aktueller Schritt Titel und Beschreibung */}
|
||||||
<div style={{ textAlign: 'center', marginBottom: '1.5rem' }}>
|
<div style={{ textAlign: 'center', marginBottom: '1.5rem' }}>
|
||||||
<h2 style={{
|
<h2 style={{
|
||||||
fontSize: '1.5rem',
|
fontSize: '1.5rem',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
color: '#2c3e50'
|
color: '#2c3e50'
|
||||||
}}>
|
}}>
|
||||||
{steps[currentStep].title}
|
{steps[currentStep].title}
|
||||||
</h2>
|
</h2>
|
||||||
{steps[currentStep].subtitle && (
|
{steps[currentStep].subtitle && (
|
||||||
<p style={{
|
<p style={{
|
||||||
color: '#6c757d',
|
color: '#6c757d',
|
||||||
fontSize: '1rem'
|
fontSize: '1rem'
|
||||||
}}>
|
}}>
|
||||||
@@ -633,9 +633,9 @@ const Setup: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigations-Buttons */}
|
{/* Navigations-Buttons */}
|
||||||
<div style={{
|
<div style={{
|
||||||
marginTop: '2rem',
|
marginTop: '2rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}}>
|
}}>
|
||||||
@@ -655,7 +655,7 @@ const Setup: React.FC = () => {
|
|||||||
>
|
>
|
||||||
← Zurück
|
← Zurück
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={goToNextStep}
|
onClick={goToNextStep}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
@@ -677,10 +677,10 @@ const Setup: React.FC = () => {
|
|||||||
|
|
||||||
{/* Zusätzliche Informationen */}
|
{/* Zusätzliche Informationen */}
|
||||||
{currentStep === 2 && !loading && (
|
{currentStep === 2 && !loading && (
|
||||||
<div style={{
|
<div style={{
|
||||||
marginTop: '1.5rem',
|
marginTop: '1.5rem',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: '#6c757d',
|
color: '#6c757d',
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
backgroundColor: '#f8f9fa',
|
backgroundColor: '#f8f9fa',
|
||||||
|
|||||||
Reference in New Issue
Block a user