Image 2
This commit is contained in:
parent
eb3516bfb2
commit
a3ec9ae318
1
exam/dist/assets/index-Bw9FCd3M.js
vendored
Normal file
1
exam/dist/assets/index-Bw9FCd3M.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
exam/dist/assets/index-CMO4zI4G.js
vendored
1
exam/dist/assets/index-CMO4zI4G.js
vendored
File diff suppressed because one or more lines are too long
2
exam/dist/index.html
vendored
2
exam/dist/index.html
vendored
@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/phpCourse/exam/dist/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/phpCourse/exam/dist/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + React + TS</title>
|
<title>Vite + React + TS</title>
|
||||||
<script type="module" crossorigin src="/phpCourse/exam/dist/assets/index-CMO4zI4G.js"></script>
|
<script type="module" crossorigin src="/phpCourse/exam/dist/assets/index-Bw9FCd3M.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/react-DXd9vB-a.js">
|
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/react-DXd9vB-a.js">
|
||||||
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/mui-CxHUbSMi.js">
|
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/mui-CxHUbSMi.js">
|
||||||
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/tanstack-xmxrKlZO.js">
|
<link rel="modulepreload" crossorigin href="/phpCourse/exam/dist/assets/tanstack-xmxrKlZO.js">
|
||||||
|
|||||||
2
exam/dist/stats.html
vendored
2
exam/dist/stats.html
vendored
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@ class ApiImpl {
|
|||||||
private token?: string;
|
private token?: string;
|
||||||
private refreshToken?: string;
|
private refreshToken?: string;
|
||||||
private self?: User;
|
private self?: User;
|
||||||
|
private userListeners: ((user?: User) => void)[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (instance) {
|
if (instance) {
|
||||||
@ -26,10 +27,19 @@ class ApiImpl {
|
|||||||
public getAuthenticatedUser = () => this.self;
|
public getAuthenticatedUser = () => this.self;
|
||||||
public getCurrentSession = () => [this.token, this.refreshToken];
|
public getCurrentSession = () => [this.token, this.refreshToken];
|
||||||
|
|
||||||
|
public subscribeToAuthenticatedUser = (callback: (user?: User) => void) => {
|
||||||
|
this.userListeners.push(callback);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this.userListeners = this.userListeners.filter((item) => item !== callback);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
public logIn = async (email: string, password: string): Promise<void> => {
|
public logIn = async (email: string, password: string): Promise<void> => {
|
||||||
const { user, token } = await (await this.post('login', { email, password })).json();
|
const { user, token } = await (await this.post('login', { email, password })).json();
|
||||||
this.self = user;
|
this.self = user;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
|
this.userListeners.forEach((listener) => listener(user));
|
||||||
};
|
};
|
||||||
|
|
||||||
public logOut = async (): Promise<boolean> => {
|
public logOut = async (): Promise<boolean> => {
|
||||||
@ -40,6 +50,7 @@ class ApiImpl {
|
|||||||
} finally {
|
} finally {
|
||||||
this.self = undefined;
|
this.self = undefined;
|
||||||
this.token = undefined;
|
this.token = undefined;
|
||||||
|
this.userListeners.forEach((listener) => listener());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,6 +73,7 @@ class ApiImpl {
|
|||||||
public updateUser = async (data: UserUpdate, id?: number): Promise<User> => {
|
public updateUser = async (data: UserUpdate, id?: number): Promise<User> => {
|
||||||
const user = await (await this.patch(`users/${id ?? 'self'}`, data as Record<string, unknown>)).json();
|
const user = await (await this.patch(`users/${id ?? 'self'}`, data as Record<string, unknown>)).json();
|
||||||
this.self = user;
|
this.self = user;
|
||||||
|
this.userListeners.forEach((listener) => listener(user));
|
||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,6 +84,7 @@ class ApiImpl {
|
|||||||
|
|
||||||
const user = await (await this.postAuthRaw(`users/${id ?? 'self'}/image`, formData)).json();
|
const user = await (await this.postAuthRaw(`users/${id ?? 'self'}/image`, formData)).json();
|
||||||
this.self = user;
|
this.self = user;
|
||||||
|
this.userListeners.forEach((listener) => listener(user));
|
||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -168,14 +168,18 @@ const UserImageDialog: FC<Props> = ({ user, open, onClose }) => {
|
|||||||
<InputLabel size="small">{t('Predefined')}</InputLabel>
|
<InputLabel size="small">{t('Predefined')}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
name={field.name}
|
name={field.name}
|
||||||
value={field.state.value}
|
value={field.state.value ?? ''}
|
||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
onChange={(e) => field.handleChange(e.target.value)}
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
size="small"
|
size="small"
|
||||||
label={t('Predefined')}
|
label={t('Predefined')}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
//renderValue={(selected) => selected ?? 'Keine Auswahl'}
|
||||||
>
|
>
|
||||||
|
<MenuItem value="" selected>
|
||||||
|
Keine Auswahl
|
||||||
|
</MenuItem>
|
||||||
{[...Array(10).keys()].map((i) => (
|
{[...Array(10).keys()].map((i) => (
|
||||||
<MenuItem key={`avatar-${i + 1}`} value={`avatar-${i + 1}`}>
|
<MenuItem key={`avatar-${i + 1}`} value={`avatar-${i + 1}`}>
|
||||||
{t('Avatar', { name: i + 1 })}
|
{t('Avatar', { name: i + 1 })}
|
||||||
|
|||||||
@ -10,9 +10,10 @@ import {
|
|||||||
useScrollTrigger,
|
useScrollTrigger,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Link, useRouterState } from '@tanstack/react-router';
|
import { Link, useRouterState } from '@tanstack/react-router';
|
||||||
import { cloneElement, FC, ReactElement, useState } from 'react';
|
import { cloneElement, FC, ReactElement, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Api from '../../api/Api';
|
import Api from '../../api/Api';
|
||||||
|
import { User } from '../../types/User';
|
||||||
import LanguageMenu from '../Menus/Language/LanguageMenu';
|
import LanguageMenu from '../Menus/Language/LanguageMenu';
|
||||||
import UserMenu from '../Menus/User/UserMenu';
|
import UserMenu from '../Menus/User/UserMenu';
|
||||||
|
|
||||||
@ -30,11 +31,12 @@ const ElevationScroll = ({ children }: { children: ReactElement }) => {
|
|||||||
const Header: FC = () => {
|
const Header: FC = () => {
|
||||||
const [anchorUserMenu, setAnchorUserMenu] = useState<null | HTMLElement>(null);
|
const [anchorUserMenu, setAnchorUserMenu] = useState<null | HTMLElement>(null);
|
||||||
const [anchorLanguageMenu, setAnchorLanguageMenu] = useState<null | HTMLElement>(null);
|
const [anchorLanguageMenu, setAnchorLanguageMenu] = useState<null | HTMLElement>(null);
|
||||||
|
const [user, setUser] = useState<User>();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isLoading = useRouterState({ select: (s) => s.status === 'pending' });
|
const isLoading = useRouterState({ select: (s) => s.status === 'pending' });
|
||||||
|
|
||||||
const user = Api.getAuthenticatedUser();
|
useEffect(() => Api.subscribeToAuthenticatedUser((user) => setUser(user)), []);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorLanguageMenu(null);
|
setAnchorLanguageMenu(null);
|
||||||
@ -52,20 +54,23 @@ const Header: FC = () => {
|
|||||||
</MUILink>
|
</MUILink>
|
||||||
{isLoading && <CircularProgress size={16} thickness={10} sx={{ color: 'white' }} />}
|
{isLoading && <CircularProgress size={16} thickness={10} sx={{ color: 'white' }} />}
|
||||||
</Box>
|
</Box>
|
||||||
<IconButton size="large" onClick={(event) => setAnchorLanguageMenu(event.currentTarget)}>
|
|
||||||
<Translate sx={{ color: 'white' }} />
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
</IconButton>
|
<IconButton size="large" onClick={(event) => setAnchorLanguageMenu(event.currentTarget)}>
|
||||||
{user ? (
|
<Translate sx={{ color: 'white' }} />
|
||||||
<IconButton onClick={(event) => setAnchorUserMenu(event.currentTarget)} sx={{ p: 0 }}>
|
|
||||||
<Avatar alt={user.username} src={`storage/${user.image}`}>
|
|
||||||
<Person />
|
|
||||||
</Avatar>
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
) : (
|
{user ? (
|
||||||
<IconButton size="large" onClick={(event) => setAnchorUserMenu(event.currentTarget)} color="inherit">
|
<IconButton onClick={(event) => setAnchorUserMenu(event.currentTarget)} sx={{ p: 0 }}>
|
||||||
<AccountCircle />
|
<Avatar alt={user.username} src={`storage/${user.image}`}>
|
||||||
</IconButton>
|
<Person />
|
||||||
)}
|
</Avatar>
|
||||||
|
</IconButton>
|
||||||
|
) : (
|
||||||
|
<IconButton size="large" onClick={(event) => setAnchorUserMenu(event.currentTarget)} color="inherit">
|
||||||
|
<AccountCircle />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
<LanguageMenu anchorEl={anchorLanguageMenu} handleClose={handleClose} />
|
<LanguageMenu anchorEl={anchorLanguageMenu} handleClose={handleClose} />
|
||||||
<UserMenu anchorEl={anchorUserMenu} handleClose={handleClose} />
|
<UserMenu anchorEl={anchorUserMenu} handleClose={handleClose} />
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user