feat: show teams

This commit is contained in:
julius 2025-03-17 19:26:09 +01:00
parent 3441e405a6
commit 054508cf6a
Signed by: julius
GPG Key ID: C80A63E6A5FD7092
7 changed files with 60 additions and 11 deletions

13
main.py
View File

@ -59,7 +59,7 @@ def add_players(players: list[Player]):
session.commit() session.commit()
def list_players(): async def list_players():
with Session(engine) as session: with Session(engine) as session:
statement = select(Player).order_by(Player.display_name) statement = select(Player).order_by(Player.display_name)
players = session.exec(statement).fetchall() players = session.exec(statement).fetchall()
@ -69,6 +69,11 @@ def list_players():
] ]
async def read_teams_me(user: Annotated[Player, Depends(get_current_active_user)]):
with Session(engine) as session:
return [p.teams for p in session.exec(select(P).where(P.id == user.id))][0]
def list_teams(): def list_teams():
with Session(engine) as session: with Session(engine) as session:
statement = select(Team) statement = select(Team)
@ -79,12 +84,16 @@ player_router = APIRouter(prefix="/player")
player_router.add_api_route("/list", endpoint=list_players, methods=["GET"]) player_router.add_api_route("/list", endpoint=list_players, methods=["GET"])
player_router.add_api_route("/add", endpoint=add_player, methods=["POST"]) player_router.add_api_route("/add", endpoint=add_player, methods=["POST"])
player_router.add_api_route("/me", endpoint=read_player_me, methods=["GET"]) player_router.add_api_route("/me", endpoint=read_player_me, methods=["GET"])
player_router.add_api_route("/me/teams", endpoint=read_teams_me, methods=["GET"])
player_router.add_api_route("/me/items", endpoint=read_own_items, methods=["GET"]) player_router.add_api_route("/me/items", endpoint=read_own_items, methods=["GET"])
player_router.add_api_route( player_router.add_api_route(
"/change_password", endpoint=change_password, methods=["POST"] "/change_password", endpoint=change_password, methods=["POST"]
) )
team_router = APIRouter(prefix="/team") team_router = APIRouter(
prefix="/team",
dependencies=[Security(get_current_active_user, scopes=["admin"])],
)
team_router.add_api_route("/list", endpoint=list_teams, methods=["GET"]) team_router.add_api_route("/list", endpoint=list_teams, methods=["GET"])
team_router.add_api_route("/add", endpoint=add_team, methods=["POST"]) team_router.add_api_route("/add", endpoint=add_team, methods=["POST"])

View File

@ -60,6 +60,7 @@ oauth2_scheme = CookieOAuth2(
tokenUrl="api/token", tokenUrl="api/token",
scopes={ scopes={
"analysis": "Access the results.", "analysis": "Access the results.",
"admin": "Maintain DB etc.",
}, },
) )

View File

@ -421,7 +421,7 @@ button {
.user-info { .user-info {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 8em 12em;
gap: 2px 16px; gap: 2px 16px;
div { div {

View File

@ -4,13 +4,14 @@ import { User } from "./api";
import { useTheme } from "./ThemeProvider"; import { useTheme } from "./ThemeProvider";
import { colourTheme, darkTheme, normalTheme, rainbowTheme } from "./themes"; import { colourTheme, darkTheme, normalTheme, rainbowTheme } from "./themes";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { Team } from "./types";
interface ContextMenuItem { interface ContextMenuItem {
label: string; label: string;
onClick: () => void; onClick: () => void;
} }
const UserInfo = (user: User) => { const UserInfo = (user: User, teams: Team[] | undefined) => {
return ( return (
<div className="user-info"> <div className="user-info">
<div> <div>
@ -24,17 +25,38 @@ const UserInfo = (user: User) => {
<div> <div>
<b>number: </b> <b>number: </b>
</div> </div>
<div>{user?.number ? user?.number : "-"}</div> <div>{user?.number || "-"}</div>
<div> <div>
<b>email: </b> <b>email: </b>
</div> </div>
<div>{user?.email ? user?.email : "-"}</div> <div>{user?.email || "-"}</div>
{teams && (
<>
<div>
<b>teams: </b>
</div>
<ul
style={{
margin: 0,
padding: 0,
textAlign: "left",
}}
>
{teams.map((team) => (
<li>
{team.name} (
{team.location || team.country || "location unknown"})
</li>
))}
</ul>
</>
)}
</div> </div>
); );
}; };
export default function Avatar() { export default function Avatar() {
const { user, onLogout } = useSession(); const { user, teams, onLogout } = useSession();
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
const navigate = useNavigate(); const navigate = useNavigate();
const [contextMenu, setContextMenu] = useState<{ const [contextMenu, setContextMenu] = useState<{
@ -118,9 +140,9 @@ export default function Avatar() {
const dialogRef = createRef<HTMLDialogElement>(); const dialogRef = createRef<HTMLDialogElement>();
function handleViewProfile() { function handleViewProfile() {
if (user) { if (user && teams) {
dialogRef.current?.showModal(); dialogRef.current?.showModal();
setDialog(UserInfo(user)); setDialog(UserInfo(user, teams));
} }
} }

View File

@ -5,9 +5,10 @@ import {
useEffect, useEffect,
useState, useState,
} from "react"; } from "react";
import { currentUser, logout, User } from "./api"; import { apiAuth, currentUser, logout, User } from "./api";
import { Login } from "./Login"; import { Login } from "./Login";
import Header from "./Header"; import Header from "./Header";
import { Team } from "./types";
export interface SessionProviderProps { export interface SessionProviderProps {
children: ReactNode; children: ReactNode;
@ -15,11 +16,13 @@ export interface SessionProviderProps {
export interface Session { export interface Session {
user: User | null; user: User | null;
teams: Team[] | null;
onLogout: () => void; onLogout: () => void;
} }
const sessionContext = createContext<Session>({ const sessionContext = createContext<Session>({
user: null, user: null,
teams: null,
onLogout: () => {}, onLogout: () => {},
}); });
@ -27,6 +30,7 @@ export function SessionProvider(props: SessionProviderProps) {
const { children } = props; const { children } = props;
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [teams, setTeams] = useState<Team[]>();
const [err, setErr] = useState<unknown>(null); const [err, setErr] = useState<unknown>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -44,8 +48,14 @@ export function SessionProvider(props: SessionProviderProps) {
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }
async function loadTeam() {
const teams: Team[] = await apiAuth("player/me/teams", null, "GET");
if (teams) setTeams(teams);
}
useEffect(() => { useEffect(() => {
loadUser(); loadUser();
setTimeout(() => loadTeam(), 1500);
}, []); }, []);
function onLogin(user: User) { function onLogin(user: User) {
@ -77,7 +87,7 @@ export function SessionProvider(props: SessionProviderProps) {
content = <Login onLogin={onLogin} />; content = <Login onLogin={onLogin} />;
} else } else
content = ( content = (
<sessionContext.Provider value={{ user, onLogout }}> <sessionContext.Provider value={{ user, teams, onLogout }}>
{children} {children}
</sessionContext.Provider> </sessionContext.Provider>
); );

View File

@ -1,4 +1,5 @@
import { useSession } from "./Session"; import { useSession } from "./Session";
import { Team } from "./types";
export const baseUrl = import.meta.env.VITE_BASE_URL as string; export const baseUrl = import.meta.env.VITE_BASE_URL as string;

View File

@ -32,3 +32,9 @@ export interface MVPRanking {
user: number; user: number;
mvps: number[]; mvps: number[];
} }
export interface Team {
name: string;
location: string;
country: string;
}