update
This commit is contained in:
@@ -15,8 +15,9 @@ import {
|
|||||||
CircularProgress,
|
CircularProgress,
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
|
TextField,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Settings as SettingsIcon, Notifications, Palette, Language, SettingsBrightness, LightMode, DarkMode, Widgets, Cloud, LinkOff, Forum } from '@mui/icons-material';
|
import { Settings as SettingsIcon, Notifications, Palette, Language, SettingsBrightness, LightMode, DarkMode, Widgets, Cloud, LinkOff, Forum, Badge } from '@mui/icons-material';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import DashboardLayout from '../components/dashboard/DashboardLayout';
|
import DashboardLayout from '../components/dashboard/DashboardLayout';
|
||||||
import { useThemeMode } from '../contexts/ThemeContext';
|
import { useThemeMode } from '../contexts/ThemeContext';
|
||||||
@@ -24,6 +25,8 @@ import { preferencesApi } from '../services/settings';
|
|||||||
import { WIDGETS, WidgetKey } from '../constants/widgets';
|
import { WIDGETS, WidgetKey } from '../constants/widgets';
|
||||||
import { nextcloudApi } from '../services/nextcloud';
|
import { nextcloudApi } from '../services/nextcloud';
|
||||||
import { useNotification } from '../contexts/NotificationContext';
|
import { useNotification } from '../contexts/NotificationContext';
|
||||||
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
|
import { membersService } from '../services/members';
|
||||||
|
|
||||||
const POLL_INTERVAL = 2000;
|
const POLL_INTERVAL = 2000;
|
||||||
const POLL_TIMEOUT = 5 * 60 * 1000;
|
const POLL_TIMEOUT = 5 * 60 * 1000;
|
||||||
@@ -31,7 +34,35 @@ const POLL_TIMEOUT = 5 * 60 * 1000;
|
|||||||
function Settings() {
|
function Settings() {
|
||||||
const { themeMode, setThemeMode } = useThemeMode();
|
const { themeMode, setThemeMode } = useThemeMode();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { showInfo } = useNotification();
|
const { showInfo, showSuccess, showError } = useNotification();
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
// FDISK Standesbuchnummer
|
||||||
|
const [standesNr, setStandesNr] = useState('');
|
||||||
|
const [standesNrEdited, setStandesNrEdited] = useState(false);
|
||||||
|
|
||||||
|
const { data: memberProfile, isLoading: profileLoading } = useQuery({
|
||||||
|
queryKey: ['member', user?.id],
|
||||||
|
queryFn: () => membersService.getMember(user!.id),
|
||||||
|
enabled: !!user?.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (memberProfile?.profile?.fdisk_standesbuch_nr != null) {
|
||||||
|
setStandesNr(memberProfile.profile.fdisk_standesbuch_nr);
|
||||||
|
}
|
||||||
|
}, [memberProfile]);
|
||||||
|
|
||||||
|
const standesNrMutation = useMutation({
|
||||||
|
mutationFn: (value: string) =>
|
||||||
|
membersService.updateMember(user!.id, { fdisk_standesbuch_nr: value || undefined }),
|
||||||
|
onSuccess: () => {
|
||||||
|
showSuccess('Standesbuchnummer gespeichert');
|
||||||
|
setStandesNrEdited(false);
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['member', user?.id] });
|
||||||
|
},
|
||||||
|
onError: () => showError('Speichern fehlgeschlagen'),
|
||||||
|
});
|
||||||
|
|
||||||
const { data: preferences, isLoading: prefsLoading } = useQuery({
|
const { data: preferences, isLoading: prefsLoading } = useQuery({
|
||||||
queryKey: ['user-preferences'],
|
queryKey: ['user-preferences'],
|
||||||
@@ -251,6 +282,49 @@ function Settings() {
|
|||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
{/* FDISK-Profil */}
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Card>
|
||||||
|
<CardContent>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||||
|
<Badge color="primary" sx={{ mr: 2 }} />
|
||||||
|
<Typography variant="h6">FDISK-Profil</Typography>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ mb: 2 }} />
|
||||||
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||||
|
Die Standesbuchnummer wird für die automatische FDISK-Synchronisation verwendet.
|
||||||
|
</Typography>
|
||||||
|
{profileLoading ? (
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'center', py: 1 }}>
|
||||||
|
<CircularProgress size={24} />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||||
|
<TextField
|
||||||
|
label="Standesbuchnummer"
|
||||||
|
size="small"
|
||||||
|
value={standesNr}
|
||||||
|
onChange={(e) => {
|
||||||
|
setStandesNr(e.target.value);
|
||||||
|
setStandesNrEdited(true);
|
||||||
|
}}
|
||||||
|
placeholder="z.B. 123456"
|
||||||
|
sx={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
disabled={!standesNrEdited || standesNrMutation.isPending}
|
||||||
|
onClick={() => standesNrMutation.mutate(standesNr)}
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
{/* Notification Settings */}
|
{/* Notification Settings */}
|
||||||
<Grid item xs={12} md={6}>
|
<Grid item xs={12} md={6}>
|
||||||
<Card>
|
<Card>
|
||||||
|
|||||||
@@ -171,9 +171,10 @@ export async function syncToDatabase(
|
|||||||
`UPDATE mitglieder_profile SET updated_at = NOW() WHERE user_id = $1`,
|
`UPDATE mitglieder_profile SET updated_at = NOW() WHERE user_id = $1`,
|
||||||
[userId]
|
[userId]
|
||||||
);
|
);
|
||||||
log(`Forced update ${member.vorname} ${member.zuname} (${member.standesbuchNr}): no changes, timestamp refreshed`);
|
log(`Forced ${member.vorname} ${member.zuname} (${member.standesbuchNr}): ${member.status}, ${dienstgrad ?? member.dienstgrad}, Eintritt ${member.eintrittsdatum ?? '—'}`);
|
||||||
forced++;
|
forced++;
|
||||||
} else {
|
} else {
|
||||||
|
log(`OK ${member.vorname} ${member.zuname} (${member.standesbuchNr}): ${member.status}, ${dienstgrad ?? member.dienstgrad}, Eintritt ${member.eintrittsdatum ?? '—'}`);
|
||||||
unchanged++;
|
unchanged++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,6 +219,7 @@ export async function syncToDatabase(
|
|||||||
log(`New Ausbildung: ${ausb.standesbuchNr} — ${ausb.kursname}${ausb.kursDatum ? ` (${ausb.kursDatum})` : ''}`);
|
log(`New Ausbildung: ${ausb.standesbuchNr} — ${ausb.kursname}${ausb.kursDatum ? ` (${ausb.kursDatum})` : ''}`);
|
||||||
ausbildungNew++;
|
ausbildungNew++;
|
||||||
} else {
|
} else {
|
||||||
|
log(`Updated Ausbildung: ${ausb.standesbuchNr} — ${ausb.kursname}${ausb.kursDatum ? ` (${ausb.kursDatum})` : ''}`);
|
||||||
ausbildungUpdated++;
|
ausbildungUpdated++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user