@micha.bigler/ui-core-micha 1.4.25 → 1.4.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -315,3 +315,64 @@ export async function loginWithRecoveryPassword(email, password, token) {
315
315
  const user = await fetchCurrentUser();
316
316
  return { user, needsMfa: false };
317
317
  }
318
+ /**
319
+ * Ruft eine Liste von Benutzern ab (oft mit Pagination/Search).
320
+ * Backend: GET /api/users/
321
+ */
322
+ export async function fetchUsersList(params = {}) {
323
+ try {
324
+ // params kann { page: 1, search: "...", ordering: "email" } enthalten
325
+ const res = await apiClient.get(`${USERS_BASE}/`, { params });
326
+ return res.data;
327
+ }
328
+ catch (error) {
329
+ throw normaliseApiError(error, 'Auth.USER_LIST_FAILED');
330
+ }
331
+ }
332
+ /**
333
+ * Löscht einen Benutzer.
334
+ * Backend: DELETE /api/users/{id}/
335
+ */
336
+ export async function deleteUser(userId) {
337
+ try {
338
+ await apiClient.delete(`${USERS_BASE}/${userId}/`);
339
+ }
340
+ catch (error) {
341
+ throw normaliseApiError(error, 'Auth.USER_DELETE_FAILED');
342
+ }
343
+ }
344
+ /**
345
+ * Aktualisiert die Rolle eines Benutzers über die Custom Action.
346
+ * Backend: PATCH /api/users/{id}/update-role/
347
+ */
348
+ export async function updateUserRole(userId, newRole) {
349
+ try {
350
+ const res = await apiClient.patch(`${USERS_BASE}/${userId}/update-role/`, {
351
+ role: newRole,
352
+ });
353
+ return res.data;
354
+ }
355
+ catch (error) {
356
+ throw normaliseApiError(error, 'Auth.USER_ROLE_UPDATE_FAILED');
357
+ }
358
+ }
359
+ /**
360
+ * Aktualisiert den Support-Status (z.B. is_support_agent Flag).
361
+ * Backend: PATCH /api/users/{id}/ (Standard DRF Update mit Nested Profile)
362
+ */
363
+ export async function updateUserSupportStatus(userId, isSupportAgent) {
364
+ try {
365
+ // Wir gehen davon aus, dass dein Serializer "profile" nested akzeptiert
366
+ // (siehe BaseUserSerializer.update Logik im Backend)
367
+ const payload = {
368
+ profile: {
369
+ is_support_agent: isSupportAgent,
370
+ },
371
+ };
372
+ const res = await apiClient.patch(`${USERS_BASE}/${userId}/`, payload);
373
+ return res.data;
374
+ }
375
+ catch (error) {
376
+ throw normaliseApiError(error, 'Auth.USER_SUPPORT_UPDATE_FAILED');
377
+ }
378
+ }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useState } from 'react';
3
3
  import { Box, TextField, Button, Typography, Alert, CircularProgress } from '@mui/material';
4
- import { inviteUserByAdmin } from '../auth/authApi';
4
+ import { requestInviteWithCode } from '../auth/authApi';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  export function UserInviteComponent({ apiUrl = '/api/users/' }) {
7
7
  const { t } = useTranslation();
@@ -17,7 +17,7 @@ export function UserInviteComponent({ apiUrl = '/api/users/' }) {
17
17
  setLoading(true);
18
18
  try {
19
19
  // API Call via authApi
20
- const data = await inviteUserByAdmin(inviteEmail, apiUrl);
20
+ const data = await requestInviteWithCode(inviteEmail, apiUrl);
21
21
  setInviteEmail('');
22
22
  setMessage(data.detail || t('Auth.INVITE_SENT_SUCCESS', 'Invitation sent.'));
23
23
  }
@@ -3,7 +3,7 @@ import React, { useState, useEffect } from 'react';
3
3
  import { Box, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, FormControl, InputLabel, Select, MenuItem, Button, IconButton, Tooltip, CircularProgress, Alert } from '@mui/material';
4
4
  import DeleteIcon from '@mui/icons-material/Delete';
5
5
  import { useTranslation } from 'react-i18next';
6
- import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi'; // Nur noch authApi!
6
+ import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi';
7
7
  const DEFAULT_ROLES = ['none', 'student', 'teacher', 'admin'];
8
8
  export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/', currentUser }) {
9
9
  const { t } = useTranslation();
package/dist/index.js CHANGED
@@ -1,17 +1,22 @@
1
- // Auth Core & Hooks
2
- export { authApi } from './auth/authApi';
1
+ // index.js (Entry Point deiner Library)
2
+ // --- 1. Auth Context (Essentiell für den Wrapper) ---
3
3
  export { AuthContext, AuthProvider } from './auth/AuthContext';
4
- // Falls du einen Custom Hook hast: export { useAuth } from './auth/react/useAuth';
5
- // Components
4
+ // --- 2. API & Services (Neue Struktur) ---
5
+ // Statt dem 'authApi'-Objekt exportieren wir die Funktionen direkt.
6
+ // Konsumenten können dann machen: import { loginWithPassword } from 'django-core-micha';
7
+ export * from './auth/authApi'; // Reine HTTP-Funktionen
8
+ export * from './utils/authService'; // Service-Funktionen (Passkeys, Social)
9
+ // --- 3. Layouts ---
6
10
  export { NarrowPage, WidePage } from './layout/PageLayout';
11
+ // --- 4. Pages (Vollständige Seiten für Routing) ---
7
12
  export { LoginPage } from './pages/LoginPage';
8
13
  export { PasswordResetRequestPage } from './pages/PasswordResetRequestPage';
9
14
  export { PasswordChangePage } from './pages/PasswordChangePage';
10
15
  export { PasswordInvitePage } from './pages/PasswordInvitePage';
16
+ export { SignUpPage } from './pages/SignUpPage';
11
17
  export { AccountPage } from './pages/AccountPage';
18
+ // --- 5. Components (Wiederverwendbare UI-Teile) ---
12
19
  export { ProfileComponent } from './components/ProfileComponent';
13
- export { SignUpPage } from './pages/SignUpPage';
14
20
  export { AccessCodeManager } from './components/AccessCodeManager';
21
+ // --- 6. Translations ---
15
22
  export { authTranslations } from './i18n/authTranslations';
16
- // Falls du noch pure UI-Komponenten hast (Formulare)
17
- // export { default as LoginForm } from './components/forms/LoginForm';
@@ -13,7 +13,7 @@ import { UserInviteComponent } from '../components/UserInviteComponent';
13
13
  import { AccessCodeManager } from '../components/AccessCodeManager';
14
14
  import { SupportRecoveryRequestsTab } from '../components/SupportRecoveryRequestsTab';
15
15
  import { AuthContext } from '../auth/AuthContext';
16
- import { authApi } from '../auth/authApi';
16
+ import { updateUserProfile } from '../auth/authApi';
17
17
  /**
18
18
  * Vollständige, selbst-konfigurierende Account-Seite.
19
19
  * * Architektur:
@@ -38,7 +38,7 @@ export function AccountPage() {
38
38
  setSearchParams({ tab: newValue });
39
39
  };
40
40
  const handleProfileSubmit = async (payload) => {
41
- const updatedUser = await authApi.updateUserProfile(payload);
41
+ const updatedUser = await updateUserProfile(payload);
42
42
  login(updatedUser);
43
43
  };
44
44
  // 3. Dynamische Tabs bauen
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@micha.bigler/ui-core-micha",
3
- "version": "1.4.25",
3
+ "version": "1.4.27",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "private": false,
@@ -328,4 +328,64 @@ export async function loginWithRecoveryPassword(email, password, token) {
328
328
  }
329
329
  const user = await fetchCurrentUser();
330
330
  return { user, needsMfa: false };
331
+ }
332
+ /**
333
+ * Ruft eine Liste von Benutzern ab (oft mit Pagination/Search).
334
+ * Backend: GET /api/users/
335
+ */
336
+ export async function fetchUsersList(params = {}) {
337
+ try {
338
+ // params kann { page: 1, search: "...", ordering: "email" } enthalten
339
+ const res = await apiClient.get(`${USERS_BASE}/`, { params });
340
+ return res.data;
341
+ } catch (error) {
342
+ throw normaliseApiError(error, 'Auth.USER_LIST_FAILED');
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Löscht einen Benutzer.
348
+ * Backend: DELETE /api/users/{id}/
349
+ */
350
+ export async function deleteUser(userId) {
351
+ try {
352
+ await apiClient.delete(`${USERS_BASE}/${userId}/`);
353
+ } catch (error) {
354
+ throw normaliseApiError(error, 'Auth.USER_DELETE_FAILED');
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Aktualisiert die Rolle eines Benutzers über die Custom Action.
360
+ * Backend: PATCH /api/users/{id}/update-role/
361
+ */
362
+ export async function updateUserRole(userId, newRole) {
363
+ try {
364
+ const res = await apiClient.patch(`${USERS_BASE}/${userId}/update-role/`, {
365
+ role: newRole,
366
+ });
367
+ return res.data;
368
+ } catch (error) {
369
+ throw normaliseApiError(error, 'Auth.USER_ROLE_UPDATE_FAILED');
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Aktualisiert den Support-Status (z.B. is_support_agent Flag).
375
+ * Backend: PATCH /api/users/{id}/ (Standard DRF Update mit Nested Profile)
376
+ */
377
+ export async function updateUserSupportStatus(userId, isSupportAgent) {
378
+ try {
379
+ // Wir gehen davon aus, dass dein Serializer "profile" nested akzeptiert
380
+ // (siehe BaseUserSerializer.update Logik im Backend)
381
+ const payload = {
382
+ profile: {
383
+ is_support_agent: isSupportAgent,
384
+ },
385
+ };
386
+ const res = await apiClient.patch(`${USERS_BASE}/${userId}/`, payload);
387
+ return res.data;
388
+ } catch (error) {
389
+ throw normaliseApiError(error, 'Auth.USER_SUPPORT_UPDATE_FAILED');
390
+ }
331
391
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react';
2
2
  import { Box, TextField, Button, Typography, Alert, CircularProgress } from '@mui/material';
3
- import { inviteUserByAdmin } from '../auth/authApi';
3
+ import { requestInviteWithCode } from '../auth/authApi';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  export function UserInviteComponent({ apiUrl = '/api/users/' }) {
@@ -18,7 +18,7 @@ export function UserInviteComponent({ apiUrl = '/api/users/' }) {
18
18
  setLoading(true);
19
19
  try {
20
20
  // API Call via authApi
21
- const data = await inviteUserByAdmin(inviteEmail, apiUrl);
21
+ const data = await requestInviteWithCode(inviteEmail, apiUrl);
22
22
 
23
23
  setInviteEmail('');
24
24
  setMessage(data.detail || t('Auth.INVITE_SENT_SUCCESS', 'Invitation sent.'));
@@ -6,7 +6,7 @@ import {
6
6
  } from '@mui/material';
7
7
  import DeleteIcon from '@mui/icons-material/Delete';
8
8
  import { useTranslation } from 'react-i18next';
9
- import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi'; // Nur noch authApi!
9
+ import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi';
10
10
 
11
11
  const DEFAULT_ROLES = ['none', 'student', 'teacher', 'admin'];
12
12
 
package/src/index.js CHANGED
@@ -1,20 +1,28 @@
1
- // Auth Core & Hooks
2
- export { authApi } from './auth/authApi';
1
+ // index.js (Entry Point deiner Library)
2
+
3
+ // --- 1. Auth Context (Essentiell für den Wrapper) ---
3
4
  export { AuthContext, AuthProvider } from './auth/AuthContext';
4
- // Falls du einen Custom Hook hast: export { useAuth } from './auth/react/useAuth';
5
5
 
6
- // Components
6
+ // --- 2. API & Services (Neue Struktur) ---
7
+ // Statt dem 'authApi'-Objekt exportieren wir die Funktionen direkt.
8
+ // Konsumenten können dann machen: import { loginWithPassword } from 'django-core-micha';
9
+ export * from './auth/authApi'; // Reine HTTP-Funktionen
10
+ export * from './utils/authService'; // Service-Funktionen (Passkeys, Social)
11
+
12
+ // --- 3. Layouts ---
7
13
  export { NarrowPage, WidePage } from './layout/PageLayout';
8
14
 
15
+ // --- 4. Pages (Vollständige Seiten für Routing) ---
9
16
  export { LoginPage } from './pages/LoginPage';
10
17
  export { PasswordResetRequestPage } from './pages/PasswordResetRequestPage';
11
18
  export { PasswordChangePage } from './pages/PasswordChangePage';
12
19
  export { PasswordInvitePage } from './pages/PasswordInvitePage';
20
+ export { SignUpPage } from './pages/SignUpPage';
13
21
  export { AccountPage } from './pages/AccountPage';
22
+
23
+ // --- 5. Components (Wiederverwendbare UI-Teile) ---
14
24
  export { ProfileComponent } from './components/ProfileComponent';
15
- export { SignUpPage } from './pages/SignUpPage';
16
25
  export { AccessCodeManager } from './components/AccessCodeManager';
17
- export { authTranslations } from './i18n/authTranslations';
18
26
 
19
- // Falls du noch pure UI-Komponenten hast (Formulare)
20
- // export { default as LoginForm } from './components/forms/LoginForm';
27
+ // --- 6. Translations ---
28
+ export { authTranslations } from './i18n/authTranslations';
@@ -20,7 +20,7 @@ import { UserInviteComponent } from '../components/UserInviteComponent';
20
20
  import { AccessCodeManager } from '../components/AccessCodeManager';
21
21
  import { SupportRecoveryRequestsTab } from '../components/SupportRecoveryRequestsTab';
22
22
  import { AuthContext } from '../auth/AuthContext';
23
- import { authApi } from '../auth/authApi';
23
+ import { updateUserProfile } from '../auth/authApi';
24
24
 
25
25
  /**
26
26
  * Vollständige, selbst-konfigurierende Account-Seite.
@@ -51,7 +51,7 @@ export function AccountPage() {
51
51
  };
52
52
 
53
53
  const handleProfileSubmit = async (payload) => {
54
- const updatedUser = await authApi.updateUserProfile(payload);
54
+ const updatedUser = await updateUserProfile(payload);
55
55
  login(updatedUser);
56
56
  };
57
57