Merge branch 'main' of github.com:Central-University-IT-prod/PROD-Animulichki-SkillHub
This commit is contained in:
@@ -5,6 +5,7 @@ from api.users.views import (
|
|||||||
DownloadUsersFromExcelView,
|
DownloadUsersFromExcelView,
|
||||||
RegisterUsersFromExcelView,
|
RegisterUsersFromExcelView,
|
||||||
UserViewSet,
|
UserViewSet,
|
||||||
|
UsersByEvent,
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = "users"
|
app_name = "users"
|
||||||
@@ -15,6 +16,11 @@ router.register("", UserViewSet)
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", include(router.urls)),
|
path("", include(router.urls)),
|
||||||
|
path(
|
||||||
|
"by-event/<event_id>/",
|
||||||
|
UsersByEvent.as_view(),
|
||||||
|
name="users-by-event",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"upload/excel/<event_id>/",
|
"upload/excel/<event_id>/",
|
||||||
RegisterUsersFromExcelView.as_view(),
|
RegisterUsersFromExcelView.as_view(),
|
||||||
@@ -24,5 +30,5 @@ urlpatterns = [
|
|||||||
"download/excel/<event_id>/",
|
"download/excel/<event_id>/",
|
||||||
DownloadUsersFromExcelView.as_view(),
|
DownloadUsersFromExcelView.as_view(),
|
||||||
name="excel-download",
|
name="excel-download",
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,6 +18,22 @@ class UserViewSet(ModelViewSet):
|
|||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class UsersByEvent(APIView):
|
||||||
|
def get(self, _, event_id):
|
||||||
|
try:
|
||||||
|
event = Event.objects.get(pk=event_id)
|
||||||
|
except Event.DoesNotExist:
|
||||||
|
return Response(
|
||||||
|
{"error": "Event does not exist"},
|
||||||
|
status=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
|
||||||
|
users = event.users.all()
|
||||||
|
serializer = UserSerializer(users, many=True)
|
||||||
|
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
class RegisterUsersFromExcelView(APIView):
|
class RegisterUsersFromExcelView(APIView):
|
||||||
def post(self, request, event_id):
|
def post(self, request, event_id):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 50px;
|
gap: 50px;
|
||||||
margin-top: 40px;
|
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
}
|
}
|
||||||
|
.full-content{
|
||||||
|
padding-top: 80px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.card{
|
||||||
|
max-width: 800px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,23 +8,58 @@ import less from "./Admin.module.less";
|
|||||||
import PlayerCard from "../../entities/PlayerCard/PlayerCard";
|
import PlayerCard from "../../entities/PlayerCard/PlayerCard";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CreateTeam from "../../widgets/CreateTeams/CreateTeams";
|
import CreateTeam from "../../widgets/CreateTeams/CreateTeams";
|
||||||
|
import { UserList } from "../AdminEventPage/AdminEventAPI";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "../../shared/ui/card"
|
||||||
|
|
||||||
|
|
||||||
const AdminPage = () => {
|
const AdminPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
||||||
|
const [players, setPlayerList] = useState<Event[]>([]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
var index = window.location.pathname.indexOf("/dash/admin/") + "/dash/admin/".length;
|
||||||
|
|
||||||
|
var result = window.location.pathname.substring(index);
|
||||||
|
|
||||||
|
UserList(result)
|
||||||
|
.then((data) => {
|
||||||
|
setPlayerList(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Возникла ошибка с получением:", error);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<ResizablePanelGroup direction="horizontal">
|
<ResizablePanelGroup className={less["full-content"]} direction="horizontal">
|
||||||
<ResizablePanel defaultSize={95} maxSize={95}>
|
<ResizablePanel defaultSize={60} maxSize={60}>
|
||||||
<div className={less["main-admin"]}>
|
<div className={less["main-admin"]}>
|
||||||
<Button>{t("EditTree")}</Button>
|
|
||||||
<CreateTeam />
|
<CreateTeam />
|
||||||
</div>
|
</div>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
<ResizableHandle withHandle />
|
<ResizableHandle withHandle />
|
||||||
<ResizablePanel>
|
<ResizablePanel>
|
||||||
<PlayerCard />
|
<h4>Members: {players.length}</h4>
|
||||||
<PlayerCard />
|
{players.map((event) => (
|
||||||
<PlayerCard />
|
<Card className={`${less["card"]} flex flex-row `}>
|
||||||
<PlayerCard />
|
<div className="flex flex-col">
|
||||||
|
<CardHeader className="p-0">
|
||||||
|
<CardTitle className="p-0">{`${event.first_name} | ${event.email}`}</CardTitle>
|
||||||
|
</CardHeader >
|
||||||
|
<CardContent className="p-0 mt-2">
|
||||||
|
<p>{t("skills")}:</p>
|
||||||
|
<p>{event.bio}</p>
|
||||||
|
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
</ResizablePanelGroup>
|
</ResizablePanelGroup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FormEvent } from "react";
|
import { FormEvent } from "react";
|
||||||
import { API_BASE, API_EVENT } from "../../app/APIurl";
|
import { API_BASE, API_EVENT, API_USERS } from "../../app/APIurl";
|
||||||
|
|
||||||
export const submitAddEvent = (e: FormEvent<HTMLFormElement>) => {
|
export const submitAddEvent = (e: FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -56,6 +56,8 @@ export const eventList = () => {
|
|||||||
console.error('Возникла ошибка с получением:', error);
|
console.error('Возникла ошибка с получением:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//удалить ивент
|
||||||
export const deleteEvent = (id:string) => {
|
export const deleteEvent = (id:string) => {
|
||||||
fetch(`${API_BASE}${API_EVENT}${id}`, {
|
fetch(`${API_BASE}${API_EVENT}${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
@@ -74,3 +76,33 @@ export const deleteEvent = (id:string) => {
|
|||||||
console.error('Возникла ошибка с удалением:', error);
|
console.error('Возникла ошибка с удалением:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//получение списка юзеров
|
||||||
|
export const UserList = (id:string) => {
|
||||||
|
|
||||||
|
return fetch(`${API_BASE}${API_EVENT}${id}/${API_USERS}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
console.log(response.status);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
console.log('Получил:', response.headers.get('Location'));
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
throw new Error('Код ошибки: ' + response.status);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('Успешно:', data);
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Возникла ошибка с получением:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,6 +51,14 @@
|
|||||||
justify-content:space-between;
|
justify-content:space-between;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
.model-content{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content:center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 820px) {
|
@media (max-width: 820px) {
|
||||||
.general-left{
|
.general-left{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -46,45 +46,72 @@ const Main = () => {
|
|||||||
<div className={less["general-content"]}>
|
<div className={less["general-content"]}>
|
||||||
<div className={less["general-left"]}>
|
<div className={less["general-left"]}>
|
||||||
{events.map((event) => (
|
{events.map((event) => (
|
||||||
<Card className={`${less["card"]} flex flex-row `}>
|
<Card className={`${less["card"]} flex flex-row `}>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<CardHeader className={less["header"]}>
|
<CardHeader className={less["header"]}>
|
||||||
<div className={less["up"]}>
|
<div className={less["up"]}>
|
||||||
<CardTitle className="p-0">{event.title}</CardTitle>
|
<CardTitle className="p-0">{event.title}</CardTitle>
|
||||||
<CardDescription>Дата начала: {event.start_date}</CardDescription>
|
<CardDescription>
|
||||||
</div>
|
Start Date: {event.start_date}
|
||||||
{false && (
|
</CardDescription>
|
||||||
<Button size="icon" variant="ghost" onClick={() => deleteEvent(event.id)}><TrashIcon /></Button>
|
</div>
|
||||||
)}
|
{false && (
|
||||||
</CardHeader>
|
<Button
|
||||||
<CardContent className="p-0 mt-4" >
|
size="icon"
|
||||||
<p>{event.description}</p>
|
variant="ghost"
|
||||||
</CardContent>
|
onClick={() => deleteEvent(event.id)}
|
||||||
<Dialog>
|
>
|
||||||
<DialogTrigger className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 py-2">{t("respondRequest")}</DialogTrigger>
|
<TrashIcon />
|
||||||
<DialogContent>
|
</Button>
|
||||||
<DialogHeader>
|
)}
|
||||||
<DialogTitle><h1 className={less["title-form"]}>{t("entrance")}</h1></DialogTitle>
|
</CardHeader>
|
||||||
<DialogDescription>
|
<CardContent className="p-0 mt-4">
|
||||||
<form className={less["input-form"]} onSubmit={(event) => submitRegister(event, navigate, graph)}>
|
<p>{event.description}</p>
|
||||||
<div className={less["novis"]}><Input type="text" name="event" value={event.id} placeholder="Event" /></div>
|
</CardContent>
|
||||||
<Input type="text" name="first_name" placeholder="First name" />
|
<Dialog>
|
||||||
<Input type="text" name="last_name" placeholder="Last name" />
|
<DialogTrigger className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 py-2">
|
||||||
<Input type="date" name="birth_date" placeholder="Date" />
|
{t("respondRequest")}
|
||||||
<Input type="email" name="email" placeholder="Email" />
|
</DialogTrigger>
|
||||||
<Textarea name="bio" placeholder="About" />
|
<DialogContent className={less["model-content"]}>
|
||||||
<CheckboxTree data={event.tree} setGraph={setGraph} />
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
<Button>Signup</Button>
|
<h1 className={less["title-form"]}>{t("entrance")}</h1>
|
||||||
</form>
|
</DialogTitle>
|
||||||
</DialogDescription>
|
</DialogHeader>
|
||||||
</DialogHeader>
|
<form
|
||||||
</DialogContent>
|
className={less["input-form"]}
|
||||||
</Dialog>
|
onSubmit={(event) => submitRegister(event, navigate, graph)}
|
||||||
|
>
|
||||||
|
<div className={less["novis"]}>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
name="event"
|
||||||
|
value={event.id}
|
||||||
|
placeholder="Event"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
<Input
|
||||||
))}
|
type="text"
|
||||||
|
name="first_name"
|
||||||
|
placeholder="First name"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
name="last_name"
|
||||||
|
placeholder="Last name"
|
||||||
|
/>
|
||||||
|
<Input type="date" name="birth_date" placeholder="Date" />
|
||||||
|
<Input type="email" name="email" placeholder="Email" />
|
||||||
|
<Textarea name="bio" placeholder="About" />
|
||||||
|
<CheckboxTree data={event.tree} setGraph={setGraph} />
|
||||||
|
|
||||||
|
<Button>Signup</Button>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
<Button variant="link" asChild>
|
<Button variant="link" asChild>
|
||||||
<Link to={"/dash/admin"}>{t("iorganizer")}</Link>
|
<Link to={"/dash/admin"}>{t("iorganizer")}</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
.general{
|
.general{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding-top: 100px;
|
padding-top: 80px;
|
||||||
}
|
}
|
||||||
.left{
|
.left{
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
padding: 20px;
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
.right{
|
.right{
|
||||||
width: 50%;
|
width: 50%;
|
||||||
@@ -12,4 +14,29 @@ width: 50%;
|
|||||||
}
|
}
|
||||||
.card{
|
.card{
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.input-form{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.up{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.header{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
.h2{
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { ToastAction } from "../../shared/ui/toast";
|
import { ToastAction } from "../../shared/ui/toast";
|
||||||
import { useToast } from "../../shared/ui/use-toast";
|
import { useToast } from "../../shared/ui/use-toast";
|
||||||
import { buttonVariants } from "../../ui/button";
|
import { buttonVariants } from "../../ui/button";
|
||||||
import { addEvent, submitRegister } from "../../widgets/Header/AuthAPI";
|
import { addEvent, deleteEvent, submitRegister } from "../../widgets/Header/AuthAPI";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -47,13 +47,14 @@ const SkillTree = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={less["general"]}>
|
<div className={less["general"]}>
|
||||||
<div className={less["left"]}>
|
<div className={less["left"]}>
|
||||||
|
<h2 className={less["h2"]}>Create event</h2>
|
||||||
<form className={less["input-form"]} onSubmit={(event) => addEvent(event)}>
|
<form className={less["input-form"]} onSubmit={(event) => addEvent(event)}>
|
||||||
<Input type="text" name="title" placeholder="Event name" />
|
<Input type="text" name="title" placeholder="Event name" />
|
||||||
<Input type="text" name="description" placeholder="Last name" />
|
<Input type="text" name="description" placeholder="Last name" />
|
||||||
<Input type="date" name="start_date" placeholder="Start date" />
|
<Input type="date" name="start_date" placeholder="Start date" />
|
||||||
<Input type="date" name="end_date" placeholder="End date" />
|
<Input type="date" name="end_date" placeholder="End date" />
|
||||||
<Textarea name="description" placeholder="Description" />
|
<Textarea name="description" placeholder="Description" />
|
||||||
<Switch/>
|
<Switch name="is_online"/>
|
||||||
<Button>{t("buttonLoginInSystem")}</Button>
|
<Button>{t("buttonLoginInSystem")}</Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,11 +64,11 @@ const SkillTree = () => {
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<CardHeader className={less["header"]}>
|
<CardHeader className={less["header"]}>
|
||||||
<div className={less["up"]}>
|
<div className={less["up"]}>
|
||||||
<CardTitle className="p-0">{event.title}</CardTitle>
|
<CardTitle className={less["title"]}>{event.title}</CardTitle>
|
||||||
<CardDescription>Дата начала: {event.start_date}</CardDescription>
|
<CardDescription>Start date: {event.start_date}</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
{false && (
|
{true && (
|
||||||
<Button size="icon" variant="ghost" ><TrashIcon /></Button>
|
<Button size="icon" variant="ghost"onClick={() =>{deleteEvent(event.id)}} ><TrashIcon /></Button>
|
||||||
)}
|
)}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="p-0 mt-4" >
|
<CardContent className="p-0 mt-4" >
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ i18n.use(initReactI18next).init({
|
|||||||
LightTheme: "Светлая",
|
LightTheme: "Светлая",
|
||||||
DarkTheme: "Темная",
|
DarkTheme: "Темная",
|
||||||
SystemTheme: "Тема устройства",
|
SystemTheme: "Тема устройства",
|
||||||
entrance: "Вход",
|
entrance: "Подать заявку",
|
||||||
login: "Авторизация",
|
login: "Авторизация",
|
||||||
registration: "Регистрация",
|
registration: "Регистрация",
|
||||||
loginHeader: "Введите адрес электронной почты и пароль, чтобы начать.",
|
loginHeader: "Введите адрес электронной почты и пароль, чтобы начать.",
|
||||||
@@ -58,7 +58,7 @@ i18n.use(initReactI18next).init({
|
|||||||
LightTheme: "Light",
|
LightTheme: "Light",
|
||||||
DarkTheme: "Dark",
|
DarkTheme: "Dark",
|
||||||
SystemTheme: "System Theme",
|
SystemTheme: "System Theme",
|
||||||
entrance: "Sign in",
|
entrance: "Submit An Application",
|
||||||
login: "Log in",
|
login: "Log in",
|
||||||
registration: "Sign up",
|
registration: "Sign up",
|
||||||
loginHeader: " Enter your email address and password to get started.",
|
loginHeader: " Enter your email address and password to get started.",
|
||||||
@@ -94,7 +94,7 @@ i18n.use(initReactI18next).init({
|
|||||||
LightTheme: "光",
|
LightTheme: "光",
|
||||||
DarkTheme: "黑暗",
|
DarkTheme: "黑暗",
|
||||||
SystemTheme: "系统主题",
|
SystemTheme: "系统主题",
|
||||||
entrance: "登入您的帐户",
|
entrance: "递交申请",
|
||||||
login: "登录",
|
login: "登录",
|
||||||
registration: "登记注册",
|
registration: "登记注册",
|
||||||
loginHeader: "请输入您的电子邮件地址和密码,开始更改.",
|
loginHeader: "请输入您的电子邮件地址和密码,开始更改.",
|
||||||
|
|||||||
Reference in New Issue
Block a user