participantlist works!

This commit is contained in:
2024-05-11 15:28:58 +03:00
parent 0ebfd11851
commit 175d2f9cd4
8 changed files with 136 additions and 22 deletions

View File

@ -78,7 +78,7 @@ async def read_users_me(
@router.get("/anon") @router.get("/anon")
async def get_qnon_user( async def get_anon_user(
anon_user: Annotated[schemas.AnonUser, Depends(services.get_anon_user)] anon_user: Annotated[schemas.AnonUser, Depends(services.get_anon_user)]
) -> schemas.AnonUser: ) -> schemas.AnonUser:
return anon_user return anon_user

View File

@ -5,7 +5,7 @@ from uuid import UUID
import redis import redis
import asyncio import asyncio
from ...dependencies import get_db, get_pubsub from ...dependencies import get_db, get_pubsub, get_redis
from ...db import models from ...db import models
from ..auth import services as auth_services from ..auth import services as auth_services
@ -43,7 +43,6 @@ def get_detailed_queue(
db: Annotated[Session, Depends(get_db)], db: Annotated[Session, Depends(get_db)],
) -> schemas.QueueDetail: ) -> schemas.QueueDetail:
q = db.query(models.Queue).filter(models.Queue.id == queue_id).first() q = db.query(models.Queue).filter(models.Queue.id == queue_id).first()
print("\n\n", queue_id, "\n\n", flush=True)
if q: if q:
return schemas.QueueDetail( return schemas.QueueDetail(
id=q.id, id=q.id,
@ -63,10 +62,11 @@ def get_detailed_queue(
) )
def join_queue( async def join_queue(
queue_id: UUID, queue_id: UUID,
client: Annotated[auth_schemas.AnonUser, Depends(auth_services.get_anon_user)], client: Annotated[auth_schemas.AnonUser, Depends(auth_services.get_anon_user)],
db: Annotated[Session, Depends(get_db)], db: Annotated[Session, Depends(get_db)],
r: Annotated[redis.client.Redis, Depends(get_redis)],
) -> schemas.QueueUser: ) -> schemas.QueueUser:
q = get_queue_by_id(queue_id, db) q = get_queue_by_id(queue_id, db)
if q: if q:
@ -78,6 +78,7 @@ def join_queue(
) )
db.add(new_qu) db.add(new_qu)
db.commit() db.commit()
await r.publish(str(queue_id), "updated")
return new_qu return new_qu
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, status_code=status.HTTP_409_CONFLICT,
@ -96,9 +97,8 @@ async def set_queue_listener(
) -> schemas.QueueDetail: ) -> schemas.QueueDetail:
await ps.subscribe(str(queue_id)) await ps.subscribe(str(queue_id))
async for m in ps.listen(): async for m in ps.listen():
print(m, flush=True)
if m.get("data", None) == b"updated": if m.get("data", None) == b"updated":
print("UPDATED", flush=True)
break break
await ps.unsubscribe()
new_queue = get_detailed_queue(queue_id=queue_id, db=db) new_queue = get_detailed_queue(queue_id=queue_id, db=db)
return new_queue return new_queue

View File

@ -1,9 +1,8 @@
import React, { useState } from "react"; import React, { useContext } from "react";
import "../styles.css"; import "../styles.css";
import { Button, Divider, Input, Spin } from "antd"; import { Button, Spin } from "antd";
import { import {
ArrowLeftOutlined, ArrowLeftOutlined,
CameraOutlined,
FileTextOutlined, FileTextOutlined,
PlusOutlined, PlusOutlined,
UserOutlined, UserOutlined,
@ -11,13 +10,34 @@ import {
import Title from "antd/es/typography/Title"; import Title from "antd/es/typography/Title";
import tr from "../../config/translation"; import tr from "../../config/translation";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useGetQueueDetailQuery } from "../../slice/QueueApi"; import {
useGetQueueDetailQuery,
useJoinQueueMutation,
} from "../../slice/QueueApi";
import { MessageContext } from "../../App";
const ApproveQueueJoinCard = (props: { id: string }): JSX.Element => { const ApproveQueueJoinCard = (props: { id: string }): JSX.Element => {
const navigate = useNavigate(); const navigate = useNavigate();
const { data, isFetching, isError } = useGetQueueDetailQuery(props.id, { const messageApi = useContext(MessageContext);
skip: !props.id,
}); const { data, refetch, isFetching, isError } = useGetQueueDetailQuery(
props.id,
{
skip: !props.id,
}
);
const [joinQueue, { isLoading }] = useJoinQueueMutation();
const onJoinButtonClick = () => {
joinQueue(props.id)
.unwrap()
.then(() =>
messageApi.success(tr("Successfully joined queue ") + data.name)
)
.then(() => navigate(`/queue/${props.id}`))
.then(() => refetch())
.catch((e) => messageApi.error(tr(e.data.detail)));
};
return ( return (
<div className="card"> <div className="card">
@ -48,7 +68,11 @@ const ApproveQueueJoinCard = (props: { id: string }): JSX.Element => {
{" "} {" "}
{data?.participants?.remaining} / {data?.participants?.total} {data?.participants?.remaining} / {data?.participants?.total}
</p> </p>
<Button icon={<PlusOutlined />}>{tr("Join")}</Button> <Spin spinning={isLoading}>
<Button icon={<PlusOutlined />} onClick={onJoinButtonClick}>
{tr("Join")}
</Button>
</Spin>
</div> </div>
)} )}
</Spin> </Spin>

View File

@ -13,11 +13,15 @@ import tr from "../../config/translation";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { StorePrototype } from "../../config/store"; import { StorePrototype } from "../../config/store";
import AnonUserCard from "../user/AnonUserCard";
const QueueCard = (): JSX.Element => { const QueueCard = (): JSX.Element => {
const user = useSelector((state: StorePrototype) => state.auth.user); const user = useSelector((state: StorePrototype) => state.auth.user);
const { queueId } = useParams(); const { queueId } = useParams();
const { data, isFetching } = useGetQueueDetailQuery(queueId); const { data, isFetching } = useGetQueueDetailQuery(queueId, {
skip: !queueId,
});
return ( return (
<div className="card"> <div className="card">
<Spin <Spin
@ -39,6 +43,14 @@ const QueueCard = (): JSX.Element => {
{data?.participants?.remaining} / {data?.participants?.total} {data?.participants?.remaining} / {data?.participants?.total}
</p> </p>
</div> </div>
<div>
<Title level={3} style={{ textAlign: "left" }}>
{tr("Queue participants")}
</Title>
{data?.participants.users_list.map((v) => {
return <AnonUserCard key={v.id} user={v} />;
})}
</div>
</Spin> </Spin>
</div> </div>
); );

View File

@ -101,3 +101,25 @@
.queue-info > * { .queue-info > * {
text-align: left; text-align: left;
} }
.anon-circle {
width: 50px;
height: 50px;
line-height: 50px;
border-radius: 50%;
text-align: center;
}
.anon-card {
display: flex;
flex-flow: row nowrap;
align-items: center;
animation: 0.3s ease-out 0s 1 cardPopup;
background: #001d39;
margin-top: 0.5rem;
margin-right: 1rem;
margin-left: 1rem;
border-radius: 10px;
padding: 1rem;
border: 2px solid #00d8a4;
}

View File

@ -1,7 +1,45 @@
import React from "react"; import React from "react";
import { AnonUser } from "../../slice/AuthApi";
import "../styles.css";
import tr from "../../config/translation";
import Title from "antd/es/typography/Title";
import Paragraph from "antd/es/typography/Paragraph";
const UUIDToColor = (uuid: string): string => {}; const UUIDToColor = (uuid: string): string => {
return (
const AnonUserCard = (): JSX.Element => { "#" +
return; uuid.split("-").reduce((store: string, v: string) => {
return store + v.substring(0, 1);
}, "") +
uuid.substring(uuid.length - 1)
);
}; };
const getProfileText = (name: string): string => {
return name.substring(0, 1);
};
const AnonUserCard = (props: {
user: AnonUser;
backlight?: "self" | "active" | undefined;
}): JSX.Element => {
return (
<div className="anon-card">
<div
className="anon-circle"
style={{ background: UUIDToColor(props.user.id) }}
>
{props.user.name
? getProfileText(props.user.name)
: props.user.id.substring(0, 2)}
</div>
<p color="white" style={{ marginLeft: "10px" }}>
{props.user.name
? props.user.name
: tr("Anonymous") + " #" + props.user.id.substring(0, 4)}
</p>
</div>
);
};
export default AnonUserCard;

View File

@ -24,6 +24,11 @@ export type TokenResponse = {
token_type: string; token_type: string;
}; };
export type AnonUser = {
id: string;
name: string;
};
export const AuthApi = createApi({ export const AuthApi = createApi({
reducerPath: "AuthApi", reducerPath: "AuthApi",
baseQuery: fetchBaseQuery({ baseQuery: fetchBaseQuery({

View File

@ -1,6 +1,7 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseUrl } from "../config/baseUrl"; import { baseUrl } from "../config/baseUrl";
import { RootState } from "../config/store"; import { RootState } from "../config/store";
import { AnonUser } from "./AuthApi";
export type CreateQueueRequest = { export type CreateQueueRequest = {
name: string; name: string;
@ -13,6 +14,17 @@ export type Queue = {
description: string | null; description: string | null;
}; };
export type QueueDetail = {
id: string;
name: string;
description: string | null;
participants: {
total: number;
remaining: number;
users_list: [AnonUser];
};
};
export const QueueApi = createApi({ export const QueueApi = createApi({
reducerPath: "QueueApi", reducerPath: "QueueApi",
baseQuery: fetchBaseQuery({ baseQuery: fetchBaseQuery({
@ -30,14 +42,14 @@ export const QueueApi = createApi({
}, },
}), }),
endpoints: (builder) => ({ endpoints: (builder) => ({
getQueues: builder.query({ getQueues: builder.query<[Queue], undefined>({
query: () => "/", query: () => "/",
}), }),
getQueueDetail: builder.query({ getQueueDetail: builder.query<QueueDetail, string | undefined>({
query: (queueId: string | undefined) => `/${queueId}`, query: (queueId: string | undefined) => `/${queueId}`,
}), }),
joinQueue: builder.mutation({ joinQueue: builder.mutation({
query: (queueId: string) => `/${queueId}/join`, query: (queueId: string) => ({ url: `/${queueId}/join`, method: "POST" }),
}), }),
createQueue: builder.mutation({ createQueue: builder.mutation({
query: (data: CreateQueueRequest) => ({ query: (data: CreateQueueRequest) => ({
@ -52,5 +64,6 @@ export const QueueApi = createApi({
export const { export const {
useGetQueuesQuery, useGetQueuesQuery,
useGetQueueDetailQuery, useGetQueueDetailQuery,
useJoinQueueMutation,
useCreateQueueMutation, useCreateQueueMutation,
} = QueueApi; } = QueueApi;