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" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<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/mui-CxHUbSMi.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 refreshToken?: string;
|
||||
private self?: User;
|
||||
private userListeners: ((user?: User) => void)[] = [];
|
||||
|
||||
constructor() {
|
||||
if (instance) {
|
||||
@ -26,10 +27,19 @@ class ApiImpl {
|
||||
public getAuthenticatedUser = () => this.self;
|
||||
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> => {
|
||||
const { user, token } = await (await this.post('login', { email, password })).json();
|
||||
this.self = user;
|
||||
this.token = token;
|
||||
this.userListeners.forEach((listener) => listener(user));
|
||||
};
|
||||
|
||||
public logOut = async (): Promise<boolean> => {
|
||||
@ -40,6 +50,7 @@ class ApiImpl {
|
||||
} finally {
|
||||
this.self = undefined;
|
||||
this.token = undefined;
|
||||
this.userListeners.forEach((listener) => listener());
|
||||
}
|
||||
};
|
||||
|
||||
@ -62,6 +73,7 @@ class ApiImpl {
|
||||
public updateUser = async (data: UserUpdate, id?: number): Promise<User> => {
|
||||
const user = await (await this.patch(`users/${id ?? 'self'}`, data as Record<string, unknown>)).json();
|
||||
this.self = user;
|
||||
this.userListeners.forEach((listener) => listener(user));
|
||||
return user;
|
||||
};
|
||||
|
||||
@ -72,6 +84,7 @@ class ApiImpl {
|
||||
|
||||
const user = await (await this.postAuthRaw(`users/${id ?? 'self'}/image`, formData)).json();
|
||||
this.self = user;
|
||||
this.userListeners.forEach((listener) => listener(user));
|
||||
return user;
|
||||
};
|
||||
|
||||
|
||||
@ -168,14 +168,18 @@ const UserImageDialog: FC<Props> = ({ user, open, onClose }) => {
|
||||
<InputLabel size="small">{t('Predefined')}</InputLabel>
|
||||
<Select
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
value={field.state.value ?? ''}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
size="small"
|
||||
label={t('Predefined')}
|
||||
autoComplete="off"
|
||||
fullWidth
|
||||
//renderValue={(selected) => selected ?? 'Keine Auswahl'}
|
||||
>
|
||||
<MenuItem value="" selected>
|
||||
Keine Auswahl
|
||||
</MenuItem>
|
||||
{[...Array(10).keys()].map((i) => (
|
||||
<MenuItem key={`avatar-${i + 1}`} value={`avatar-${i + 1}`}>
|
||||
{t('Avatar', { name: i + 1 })}
|
||||
|
||||
@ -10,9 +10,10 @@ import {
|
||||
useScrollTrigger,
|
||||
} from '@mui/material';
|
||||
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 Api from '../../api/Api';
|
||||
import { User } from '../../types/User';
|
||||
import LanguageMenu from '../Menus/Language/LanguageMenu';
|
||||
import UserMenu from '../Menus/User/UserMenu';
|
||||
|
||||
@ -30,11 +31,12 @@ const ElevationScroll = ({ children }: { children: ReactElement }) => {
|
||||
const Header: FC = () => {
|
||||
const [anchorUserMenu, setAnchorUserMenu] = useState<null | HTMLElement>(null);
|
||||
const [anchorLanguageMenu, setAnchorLanguageMenu] = useState<null | HTMLElement>(null);
|
||||
const [user, setUser] = useState<User>();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const isLoading = useRouterState({ select: (s) => s.status === 'pending' });
|
||||
|
||||
const user = Api.getAuthenticatedUser();
|
||||
useEffect(() => Api.subscribeToAuthenticatedUser((user) => setUser(user)), []);
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorLanguageMenu(null);
|
||||
@ -52,20 +54,23 @@ const Header: FC = () => {
|
||||
</MUILink>
|
||||
{isLoading && <CircularProgress size={16} thickness={10} sx={{ color: 'white' }} />}
|
||||
</Box>
|
||||
<IconButton size="large" onClick={(event) => setAnchorLanguageMenu(event.currentTarget)}>
|
||||
<Translate sx={{ color: 'white' }} />
|
||||
</IconButton>
|
||||
{user ? (
|
||||
<IconButton onClick={(event) => setAnchorUserMenu(event.currentTarget)} sx={{ p: 0 }}>
|
||||
<Avatar alt={user.username} src={`storage/${user.image}`}>
|
||||
<Person />
|
||||
</Avatar>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton size="large" onClick={(event) => setAnchorLanguageMenu(event.currentTarget)}>
|
||||
<Translate sx={{ color: 'white' }} />
|
||||
</IconButton>
|
||||
) : (
|
||||
<IconButton size="large" onClick={(event) => setAnchorUserMenu(event.currentTarget)} color="inherit">
|
||||
<AccountCircle />
|
||||
</IconButton>
|
||||
)}
|
||||
{user ? (
|
||||
<IconButton onClick={(event) => setAnchorUserMenu(event.currentTarget)} sx={{ p: 0 }}>
|
||||
<Avatar alt={user.username} src={`storage/${user.image}`}>
|
||||
<Person />
|
||||
</Avatar>
|
||||
</IconButton>
|
||||
) : (
|
||||
<IconButton size="large" onClick={(event) => setAnchorUserMenu(event.currentTarget)} color="inherit">
|
||||
<AccountCircle />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
<LanguageMenu anchorEl={anchorLanguageMenu} handleClose={handleClose} />
|
||||
<UserMenu anchorEl={anchorUserMenu} handleClose={handleClose} />
|
||||
</Toolbar>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user