mirror of
https://github.com/more-tech4-magnum-opus/frontend.git
synced 2024-11-22 00:26:35 +03:00
add HR
This commit is contained in:
parent
f9b70590c0
commit
6b84a11c2a
BIN
public/mock.png
Normal file
BIN
public/mock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
44
src/Transaction.tsx
Normal file
44
src/Transaction.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { Button, Input } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { adminFetcher, hrFetcher } from "./app/hooks";
|
||||
|
||||
export const Transaction:React.FC = () =>{
|
||||
const [user, setUser] = useState("")
|
||||
const [amount, setAmount] = useState(0)
|
||||
|
||||
const reset = () =>{
|
||||
setUser("")
|
||||
setAmount(0)
|
||||
}
|
||||
|
||||
const sendCoins = () =>{
|
||||
let formData = new FormData()
|
||||
formData.append("amount", amount.toString())
|
||||
formData.append("username", user)
|
||||
|
||||
hrFetcher.post("blockchain/transact/", formData).then(e=>{
|
||||
alert("Коины переведены!")
|
||||
reset()
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
return(
|
||||
<div className="addProduct">
|
||||
<div className="addProductCard">
|
||||
<div className="addProductH1">Перевод/Выдача DigitalRubles</div>
|
||||
<div className="fieldsWrapper" >
|
||||
<div className="InpWrapper">
|
||||
<div>Telegram username</div>
|
||||
<Input value={user} onChange={(e)=>setUser(e.target.value)} placeholder="firesieht"></Input>
|
||||
</div>
|
||||
<div className="InpWrapper">
|
||||
<div>Сумма в коинах</div>
|
||||
<Input value={amount} type="number" onChange={(e)=>setAmount(Number(e.target.value))} placeholder="100"></Input>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={()=>sendCoins()} className="btn1">Отправить</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap:30px
|
||||
}
|
||||
|
||||
.addProductCard{
|
||||
|
@ -110,3 +111,28 @@
|
|||
justify-content: center;
|
||||
gap:25px
|
||||
}
|
||||
|
||||
.userPreview{
|
||||
background: #262626;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 32px 64px;
|
||||
gap: 36px;
|
||||
width: 75%;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
/* identical to box height, or 157% */
|
||||
|
||||
text-align: right;
|
||||
|
||||
/* Character/Title .85 */
|
||||
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ export const AddAdminMarketProduct:React.FC = () =>{
|
|||
link:"/admin/market/add",
|
||||
name:"Cоздать товар (NFT)"
|
||||
},
|
||||
{
|
||||
link:"/admin/transaction",
|
||||
name:"История транзакций"
|
||||
},
|
||||
]}
|
||||
name={user.name}></Header>
|
||||
<div className="addProductCard">
|
||||
|
|
|
@ -60,6 +60,10 @@ export const AdminMarket:React.FC = () =>{
|
|||
link:"/admin/market/add",
|
||||
name:"Cоздать товар (NFT)"
|
||||
},
|
||||
{
|
||||
link:"/admin/transaction",
|
||||
name:"История транзакций"
|
||||
},
|
||||
]}
|
||||
name={user.name}></Header>
|
||||
<div className="marketCard">
|
||||
|
|
|
@ -43,7 +43,11 @@ export const AdminMarketPopUp:React.FC = () =>{
|
|||
{
|
||||
link:"/admin/users",
|
||||
name:"Участники"
|
||||
}
|
||||
},
|
||||
{
|
||||
link:"/admin/transaction",
|
||||
name:"История транзакций"
|
||||
},
|
||||
]}
|
||||
name={user.name}></Header>
|
||||
<div className="changeProductCard">
|
||||
|
|
7
src/admin/adminTransactions/index.tsx
Normal file
7
src/admin/adminTransactions/index.tsx
Normal file
|
@ -0,0 +1,7 @@
|
|||
import React from "react";
|
||||
|
||||
export const AdminTransactions:React.FC = () =>{
|
||||
return(<div>
|
||||
|
||||
</div>);
|
||||
}
|
|
@ -140,7 +140,7 @@ export const UserTable:React.FC = () =>{
|
|||
command: user.command,
|
||||
role: user.type,
|
||||
respect: user.respect,
|
||||
balance: user.salary,
|
||||
balance: user.money,
|
||||
jobTittle: user.department,
|
||||
clan: user.clan_name
|
||||
}) as EmployerIE ))))
|
||||
|
@ -156,7 +156,7 @@ export const UserTable:React.FC = () =>{
|
|||
command: user.command,
|
||||
role: user.type,
|
||||
respect: user.respect,
|
||||
balance: user.salary,
|
||||
balance: user.money,
|
||||
jobTittle: user.department,
|
||||
}) ))
|
||||
} as ClanIE))
|
||||
|
@ -202,6 +202,10 @@ export const UserTable:React.FC = () =>{
|
|||
link:"/admin/market/add",
|
||||
name:"Cоздать товар (NFT)"
|
||||
},
|
||||
{
|
||||
link:"/admin/transaction",
|
||||
name:"История транзакций"
|
||||
},
|
||||
|
||||
]}
|
||||
name={user.name}></Header>
|
||||
|
|
|
@ -3,8 +3,6 @@ import { stat } from 'fs'
|
|||
import { Market, Roles, SortTypes, UserIE, ProductIE, EmployerIE, ClanIE} from '../interfaces'
|
||||
import { AppAdminDispatch, RootAdminState } from '../adminStore'
|
||||
import { adminFetcher, useAppDispatch } from '../hooks'
|
||||
import { host, token } from '../consts'
|
||||
import { triggerAsyncId } from 'async_hooks'
|
||||
|
||||
|
||||
|
||||
|
@ -15,7 +13,7 @@ const initState = {
|
|||
wallet:"123214",
|
||||
balance: 100,
|
||||
id:"1",
|
||||
role:Roles.admin,
|
||||
role:"ADMIN",
|
||||
name:"Firesieht"
|
||||
} as UserIE, //потом достается запросом
|
||||
market: {
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
export const host = "https://dev.akarpov.ru/api/"
|
||||
export const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1ODI0ODQxLCJpYXQiOjE2NjUyMjQ4NDEsImp0aSI6ImIyMjgzZjg0MmQ0NjQ4ZDU5MGY3N2Y1NzU2NDU3YjUyIiwidXNlcl9pZCI6NH0.-jAQjFLV9WCZEbthdpO-JDbRaL3N3eTCNr9Vo-PAUEk"
|
||||
export const adminToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1ODcyMzQwLCJpYXQiOjE2NjUyNzIzNDAsImp0aSI6IjZkNGUxOTQ0ZTE3ZjQ4OTk4MjllYmU4Mzk2NDMwZTVlIiwidXNlcl9pZCI6Nn0.ivyEB13zMGS4liCn2N2fHUi0q9bbI8iaRWBXdiO30d4"
|
||||
export const hrToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1ODcyMzYxLCJpYXQiOjE2NjUyNzIzNjEsImp0aSI6Ijc3ZDk1ZTI2NWJkNzQ4NGRhNWY1MjYyNDE4YWQ2NzAwIiwidXNlcl9pZCI6NX0.luP2N8g_Yp3TNEwIBMYhSTSdSpUj3-QzT4PGfoYnM0k"
|
||||
export const workerToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1ODcyMzkxLCJpYXQiOjE2NjUyNzIzOTEsImp0aSI6IjBlYzQxOTUzMTA2NDRlOWFiNzE2NTgyZWJmZDY0MTBmIiwidXNlcl9pZCI6NH0.GULKUG-2iuEAVSPXdREC0wPbQbSsSaTLqQ3ZJblwtAk"
|
|
@ -1,17 +1,38 @@
|
|||
import axios from 'axios';
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||
import type { RootAdminState, AppAdminDispatch } from './adminStore';
|
||||
import { host, token } from './consts';
|
||||
import { host, adminToken, hrToken, workerToken } from './consts';
|
||||
import { AppHRDispatch, RootHRState } from './hrStore';
|
||||
|
||||
// Use throughout your app instead of plain `useDispatch` and `useSelector`
|
||||
export const useAppDispatch = () => useDispatch<AppAdminDispatch>();
|
||||
export const useHRDispatch = () => useDispatch<AppHRDispatch>();
|
||||
export const useAppSelector: TypedUseSelectorHook<RootAdminState> = useSelector;
|
||||
export const useHRSelector: TypedUseSelectorHook<RootHRState> = useSelector;
|
||||
export const adminFetcher = axios.create(
|
||||
{
|
||||
baseURL: host,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token
|
||||
Authorization: 'Bearer ' + adminToken
|
||||
}
|
||||
}
|
||||
)
|
||||
export const hrFetcher = axios.create(
|
||||
{
|
||||
baseURL: host,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + hrToken
|
||||
}
|
||||
}
|
||||
)
|
||||
export const workerFetcher = axios.create(
|
||||
{
|
||||
baseURL: host,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + workerToken
|
||||
}
|
||||
}
|
||||
)
|
158
src/app/hr/hrSlice.ts
Normal file
158
src/app/hr/hrSlice.ts
Normal file
|
@ -0,0 +1,158 @@
|
|||
import { createAsyncThunk, createSlice, createSelector, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { EventAttendence, EventIE, HRIE} from '../interfaces'
|
||||
import { AppHRDispatch, RootHRState } from '../hrStore'
|
||||
import { hrFetcher, useAppDispatch } from '../hooks'
|
||||
|
||||
|
||||
const initState = {
|
||||
me: {} as HRIE,
|
||||
events: [] as EventIE[],
|
||||
currentEvent: "",
|
||||
attendences: [] as EventAttendence[],
|
||||
}
|
||||
|
||||
const hrSlice = createSlice(
|
||||
{
|
||||
name: "hrSlice",
|
||||
initialState: initState,
|
||||
reducers:{
|
||||
setMe(state, action:PayloadAction<HRIE>){
|
||||
state.me = action.payload
|
||||
},
|
||||
setEvents(state, action:PayloadAction<EventIE[]>){
|
||||
state.events = action.payload
|
||||
},
|
||||
setAttendences(state, action:PayloadAction<EventAttendence[]>){
|
||||
state.attendences = action.payload
|
||||
},
|
||||
setCurrentEvent(state, aaction:PayloadAction<string>){
|
||||
state.currentEvent = aaction.payload
|
||||
},
|
||||
addEvent(state, action:PayloadAction<EventIE>){
|
||||
state.events = state.events.concat([action.payload])
|
||||
},
|
||||
delEvent(state, action:PayloadAction<string>){
|
||||
let events = state.events
|
||||
let ind = 0
|
||||
|
||||
events.forEach((event:EventIE, index:number) => {
|
||||
if(event.slug == action.payload){
|
||||
ind = index
|
||||
}
|
||||
});
|
||||
events.splice(ind, 1)
|
||||
state.events = events
|
||||
},
|
||||
updateEvent(state, action:PayloadAction<EventIE>){
|
||||
let events = state.events
|
||||
events.forEach((event:EventIE, index:number) => {
|
||||
if(event.slug == action.payload.slug){
|
||||
events[index] = action.payload
|
||||
}
|
||||
});
|
||||
state.events = events
|
||||
},
|
||||
submitAttendance(state, action:PayloadAction<string>){
|
||||
let attendences = state.attendences
|
||||
|
||||
attendences.forEach((attendance:EventAttendence, index:number) => {
|
||||
if(attendance.worker_username == action.payload){
|
||||
attendences[index].attended = true
|
||||
}
|
||||
});
|
||||
state.attendences = attendences
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
export async function fetchAddEvent(dispatch:AppHRDispatch, params:{name: string, about: string, starts:string, image:File}) {
|
||||
//тут идет фетч
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append("name",params.name)
|
||||
formData.append("about",params.about)
|
||||
formData.append("image", params.image)
|
||||
formData.append("starts",params.starts)
|
||||
|
||||
hrFetcher.post("events/", formData).then((response)=>{
|
||||
dispatch(
|
||||
addEvent(
|
||||
{
|
||||
name: response.data.name,
|
||||
about: response.data.about,
|
||||
slug: response.data.slug,
|
||||
creator: {
|
||||
wallet: "",
|
||||
role: response.data.creator.type,
|
||||
telegram: response.data.creator.telegram,
|
||||
command: response.data.creator.command,
|
||||
respect: response.data.creator.respect,
|
||||
balance: response.data.creator.money,
|
||||
name: response.data.creator.name
|
||||
} as HRIE,
|
||||
starts: response.data.starts,
|
||||
image: response.data.image,
|
||||
planning: Number(response.data.planning),
|
||||
attended: Number(response.data.attended)
|
||||
} as EventIE
|
||||
)
|
||||
)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export async function fetchDelEvent(dispatch:AppHRDispatch, params:string) {
|
||||
|
||||
hrFetcher.delete("events/" + params).then(()=>{
|
||||
dispatch(delEvent(params))
|
||||
})
|
||||
}
|
||||
|
||||
export async function fetchSubmitAttendance(dispatch:AppHRDispatch, user:string, currentEvent:string){
|
||||
const formData = new FormData()
|
||||
formData.append("username", user)
|
||||
|
||||
hrFetcher.post("events/attendance/" + currentEvent + "/submit/", formData).then(response=>{
|
||||
dispatch(submitAttendance(user))
|
||||
})
|
||||
|
||||
const salaryData = new FormData()
|
||||
salaryData.append("username", user)
|
||||
salaryData.append("amount", "1")
|
||||
hrFetcher.post("blockchain/transact/", salaryData)
|
||||
}
|
||||
|
||||
|
||||
export const getCurrentEvent = createSelector(
|
||||
(state:RootHRState) => state.hrSlice.events.filter(el=> el.slug == state.hrSlice.currentEvent)[0],
|
||||
(field)=>field
|
||||
)
|
||||
export const getEvents = createSelector(
|
||||
(state:RootHRState) => state.hrSlice.events,
|
||||
(field)=>field
|
||||
)
|
||||
export const getMe = createSelector(
|
||||
(state:RootHRState) => state.hrSlice.me,
|
||||
(field)=>field
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
export const {
|
||||
setEvents,
|
||||
setAttendences,
|
||||
setCurrentEvent,
|
||||
addEvent,
|
||||
delEvent,
|
||||
updateEvent,
|
||||
submitAttendance,
|
||||
setMe
|
||||
} = hrSlice.actions
|
||||
|
||||
export default hrSlice.reducer
|
16
src/app/hrStore.ts
Normal file
16
src/app/hrStore.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
|
||||
import hrSlice from './hr/hrSlice';
|
||||
export const hrStore = configureStore({
|
||||
reducer: {
|
||||
hrSlice: hrSlice,
|
||||
},
|
||||
});
|
||||
|
||||
export type AppHRDispatch = typeof hrStore.dispatch;
|
||||
export type RootHRState = ReturnType<typeof hrStore.getState>;
|
||||
export type AppHRThunk<ReturnType = void> = ThunkAction<
|
||||
ReturnType,
|
||||
RootHRState,
|
||||
unknown,
|
||||
Action<string>
|
||||
>;
|
|
@ -14,7 +14,7 @@ export enum Specialities{
|
|||
|
||||
export interface UserIE{
|
||||
wallet:string,
|
||||
role:Roles
|
||||
role:string
|
||||
balance: number,
|
||||
name:string,
|
||||
}
|
||||
|
@ -26,17 +26,32 @@ export interface EmployerIE extends UserIE{
|
|||
respect: number,
|
||||
telegramID: string,
|
||||
command: string,
|
||||
clan:string
|
||||
clan:string,
|
||||
money:number,
|
||||
}
|
||||
|
||||
export interface HRIE extends UserIE{
|
||||
respect:number,
|
||||
command:number,
|
||||
telegram: string,
|
||||
}
|
||||
|
||||
export interface EventIE{
|
||||
name:string,
|
||||
description: string,
|
||||
date: Date,
|
||||
time:Date,
|
||||
org: number;
|
||||
visitors: number[]
|
||||
about: string,
|
||||
starts: string,
|
||||
slug:string,
|
||||
creator:HRIE,
|
||||
image:string,
|
||||
planning:number,
|
||||
attended:number
|
||||
}
|
||||
|
||||
export interface EventAttendence{
|
||||
id:number,
|
||||
event_slug:string,
|
||||
worker_username:string,
|
||||
attended:boolean
|
||||
}
|
||||
|
||||
export interface ProductIE{
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import "./Header.css"
|
||||
import React from "react"
|
||||
import { Link, useLocation, useParams } from "react-router-dom"
|
||||
import axios, { AxiosHeaders } from 'axios';
|
||||
import { host, token } from "../../app/consts";
|
||||
|
||||
interface HeaderIE{
|
||||
links: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Tag } from 'antd'
|
||||
import react from 'react'
|
||||
|
||||
import "./style.css"
|
||||
|
||||
interface IUserPreview{
|
||||
level: number;
|
||||
|
|
5
src/hr/EventCard/eventCard.css
Normal file
5
src/hr/EventCard/eventCard.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
.eventImg{
|
||||
height: 50%;
|
||||
max-height: 150px;
|
||||
border-radius: 16px 16px 0px 0px;
|
||||
}
|
37
src/hr/EventCard/index.tsx
Normal file
37
src/hr/EventCard/index.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { Button } from "antd"
|
||||
import React from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { useHRDispatch } from "../../app/hooks"
|
||||
import { fetchDelEvent } from "../../app/hr/hrSlice"
|
||||
import "../../components/prevMarketCard/prevMarketCard.css"
|
||||
import "./eventCard.css"
|
||||
|
||||
interface EventCardIE{
|
||||
image:string,
|
||||
cost: number,
|
||||
descr: string,
|
||||
name:string,
|
||||
members: number
|
||||
slug?:string
|
||||
}
|
||||
|
||||
export const EventCard:React.FC<EventCardIE> = (props) =>{
|
||||
let dispatch = useHRDispatch()
|
||||
let navigator = useNavigate()
|
||||
|
||||
return(
|
||||
<div className="prevCard">
|
||||
<img className="eventImg" src={props.image}></img>
|
||||
<div className="prevCardWrapper">
|
||||
<div className="prevCost">
|
||||
<img src="/rub.svg"></img>
|
||||
<div>{props.cost}</div>
|
||||
</div>
|
||||
<div className="prevCardH2">{props.name}</div>
|
||||
<div className="prevCardDescr">{props.descr.split(" ").slice(0,6).join(" ")}</div>
|
||||
<Button style={{width:"100%"}} onClick={()=>navigator("/hr/events/reg/" + props.slug)} className="btn2">Зарегистрировать</Button>
|
||||
<Button style={{width:"100%"}} onClick={()=>fetchDelEvent(dispatch, props.slug as string)} className="btn1">Удалить ивент</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
0
src/hr/addEvent/addEvent.css
Normal file
0
src/hr/addEvent/addEvent.css
Normal file
91
src/hr/addEvent/index.tsx
Normal file
91
src/hr/addEvent/index.tsx
Normal file
|
@ -0,0 +1,91 @@
|
|||
import "./addEvent.css"
|
||||
import { Button, DatePicker, Input } from "antd";
|
||||
import React, { useState } from "react"
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useHRDispatch } from "../../app/hooks";
|
||||
import { fetchAddEvent } from "../../app/hr/hrSlice";
|
||||
import { FileUploader } from "../../components/fileUploader";
|
||||
import { Header } from "../../components/Header";
|
||||
import { EventCard } from "../EventCard";
|
||||
|
||||
|
||||
export const AddEvent: React.FC = () =>{
|
||||
|
||||
const [name, setName] = useState("")
|
||||
const [about, setAbout] = useState("")
|
||||
const [starts, setStarts] = useState("")
|
||||
const [image, setImage] = useState()
|
||||
|
||||
let navigate = useNavigate()
|
||||
let dispatch = useHRDispatch()
|
||||
|
||||
|
||||
|
||||
const create = () =>{
|
||||
fetchAddEvent(dispatch, {
|
||||
name:name,
|
||||
about:about,
|
||||
starts:starts,
|
||||
image:image as any
|
||||
})
|
||||
|
||||
alert("Ивент успешно создан!")
|
||||
|
||||
navigate("/hr")
|
||||
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="addProduct">
|
||||
<Header links={[
|
||||
{
|
||||
link:"/hr",
|
||||
name:"События"
|
||||
},
|
||||
{
|
||||
link:"/hr/addEvent",
|
||||
name:"Создать событие"
|
||||
},
|
||||
{
|
||||
link:"/hr/transaction",
|
||||
name:"История транзакций"
|
||||
}
|
||||
]}
|
||||
name={"HR"}></Header>
|
||||
<div className="addProductCard">
|
||||
<div className="addProductH1">Cоздать новое событие</div>
|
||||
<div className="addBodyWrapper">
|
||||
<EventCard
|
||||
image={"/mock.png"}
|
||||
cost={5}
|
||||
descr={about}
|
||||
name={name}
|
||||
members={2}
|
||||
></EventCard>
|
||||
<div className="fieldsWrapper">
|
||||
<div className="InpWrapper">
|
||||
<div>Название</div>
|
||||
<Input value={name} onChange={(e)=>setName(e.target.value)}></Input>
|
||||
</div>
|
||||
<div className="InpWrapper">
|
||||
<div>Описание</div>
|
||||
<Input value={about} onChange={(e)=>setAbout(e.target.value)}></Input>
|
||||
</div>
|
||||
<div className="InpWrapper">
|
||||
<div>Дата проведения</div>
|
||||
<DatePicker onChange={(_, datestring)=>setStarts(datestring)} />
|
||||
</div>
|
||||
<div className="InpWrapper">
|
||||
<div>Картинка</div>
|
||||
<FileUploader onResponse={(file)=>setImage(file)}></FileUploader>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="addBtnWrapper">
|
||||
<Button className="btn1" onClick={()=>navigate("/hr")}>Отмена</Button>
|
||||
<Button className="btn2" onClick={()=>create()}>Создать</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
100
src/hr/index.tsx
Normal file
100
src/hr/index.tsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { Tag } from "antd";
|
||||
import React from "react";
|
||||
import { hrFetcher, useAppSelector, useHRDispatch, useHRSelector } from "../app/hooks";
|
||||
import { getEvents, getMe, setEvents, setMe } from "../app/hr/hrSlice";
|
||||
import { RootHRState } from "../app/hrStore";
|
||||
import { EventIE, HRIE } from "../app/interfaces";
|
||||
import { Header } from "../components/Header";
|
||||
import { UserPreview } from "../components/userPreview";
|
||||
import { EventCard } from "./EventCard";
|
||||
|
||||
|
||||
export const HR:React.FC = () =>{
|
||||
let me = useHRSelector((state:RootHRState)=>getMe(state))
|
||||
let dispatch = useHRDispatch()
|
||||
let events = useHRSelector((state:RootHRState)=>getEvents(state))
|
||||
|
||||
|
||||
if (me.telegram == undefined){
|
||||
hrFetcher.get("users/self/").then(response=>{
|
||||
dispatch(setMe({
|
||||
wallet: response.data.wallet_public_key,
|
||||
role: response.data.type,
|
||||
telegram: response.data.telegram,
|
||||
command: response.data.command,
|
||||
respect: response.data.respect,
|
||||
balance: response.data.money,
|
||||
name: response.data.name
|
||||
} as HRIE))
|
||||
})
|
||||
hrFetcher.get("events/").then(resp=>{
|
||||
dispatch(setEvents(resp.data.map((response:any)=>({
|
||||
name: response.name,
|
||||
about: response.about,
|
||||
slug: response.slug,
|
||||
creator: {
|
||||
wallet: "",
|
||||
role: response.creator.type,
|
||||
telegram: response.creator.telegram,
|
||||
command: response.creator.command,
|
||||
respect: response.creator.respect,
|
||||
balance: response.creator.money,
|
||||
name: response.creator.name
|
||||
} as HRIE,
|
||||
starts: response.starts,
|
||||
image: response.image,
|
||||
planning: Number(response.planning),
|
||||
attended: Number(response.attended)
|
||||
} as EventIE))))
|
||||
})
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="addProduct">
|
||||
<Header links={[
|
||||
{
|
||||
link:"/hr",
|
||||
name:"События"
|
||||
},
|
||||
{
|
||||
link:"/hr/addEvent",
|
||||
name:"Создать событие"
|
||||
},
|
||||
{
|
||||
link:"/hr/transaction",
|
||||
name:"История транзакций"
|
||||
}
|
||||
]}
|
||||
name={"HR"}></Header>
|
||||
<div className="userPreview">
|
||||
<UserPreview
|
||||
level={3}
|
||||
logo_url='/logo_example.png'
|
||||
username='BrainBreaker'
|
||||
rubles={Number(me.balance).toString()}
|
||||
fio={me.name}
|
||||
id={me.command}
|
||||
tg={me.telegram}
|
||||
tags={[<Tag color={'blue'}>HR</Tag>]}
|
||||
description={"Sample"}
|
||||
score={Number(me.respect).toString()}
|
||||
></UserPreview>
|
||||
</div>
|
||||
<div className="marketCard">
|
||||
<div className="addProductH1">Доступные события</div>
|
||||
<div className="productWrapper">
|
||||
{
|
||||
events.map(event=><EventCard
|
||||
image={event.image}
|
||||
cost={5}
|
||||
descr={event.about}
|
||||
name={event.name}
|
||||
members={event.planning}
|
||||
slug={event.slug}
|
||||
></EventCard>)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
94
src/hr/regUsers/index.tsx
Normal file
94
src/hr/regUsers/index.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
import React, { useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import "./regUsers.css"
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { Button, Space, Table, Tag } from 'antd';
|
||||
import { fetchSubmitAttendance, getCurrentEvent, setCurrentEvent } from "../../app/hr/hrSlice";
|
||||
import { hrFetcher, useHRDispatch, useHRSelector } from "../../app/hooks";
|
||||
import { RootHRState } from "../../app/hrStore";
|
||||
|
||||
interface DataTypeIE{
|
||||
key:string,
|
||||
id:number,
|
||||
telegram:string,
|
||||
attended: boolean
|
||||
}
|
||||
|
||||
|
||||
export const RegUsers:React.FC = () =>{
|
||||
const [attendance, setAttendance] = useState([-1 as any])
|
||||
let {name} = useParams()
|
||||
|
||||
let navigator = useNavigate()
|
||||
const collator = new Intl.Collator('ru');
|
||||
const data:DataTypeIE[] = []
|
||||
let dispatch = useHRDispatch()
|
||||
|
||||
dispatch(setCurrentEvent(name as string))
|
||||
if (attendance[0] == -1){
|
||||
hrFetcher.get("events/attendance/"+name+"/list/").then(response=>setAttendance(response.data))
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
const columns: ColumnsType<DataTypeIE> = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
defaultSortOrder: 'descend',
|
||||
sorter: (a, b) => a.id - b.id ,
|
||||
},
|
||||
{
|
||||
title: 'Telegram',
|
||||
dataIndex: 'telegram',
|
||||
key: 'telegram',
|
||||
sorter: (a, b) => collator.compare(a.telegram, b.telegram) ,
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Респект',
|
||||
dataIndex: 'telegram',
|
||||
key: 'telegram',
|
||||
render: text=><div>{ "5"} <img src="/respect.svg"></img></div>
|
||||
},
|
||||
{
|
||||
title: 'Начислено',
|
||||
dataIndex: 'attended',
|
||||
key: 'attended',
|
||||
render: text=><Tag color={text? "green":"red"}>
|
||||
{text? "Да":"Нет"}
|
||||
</Tag>
|
||||
},
|
||||
{
|
||||
title: "Награда",
|
||||
dataIndex: 'speciality',
|
||||
key: 'speciality',
|
||||
render: (_, recorder) => <Button onClick={()=>fetchSubmitAttendance(dispatch, recorder.telegram,name as string)} className="btn2">Начислить</Button>
|
||||
}
|
||||
]
|
||||
|
||||
attendance.forEach((attend)=>{
|
||||
data.push({
|
||||
key:attend.id,
|
||||
id: attend.id,
|
||||
telegram: attend.worker_username,
|
||||
attended: attend.attended
|
||||
} as DataTypeIE)
|
||||
})
|
||||
|
||||
let currentEvent = useHRSelector((state:RootHRState)=>getCurrentEvent(state))
|
||||
|
||||
|
||||
return(
|
||||
<div className="userTable">
|
||||
<div className="changeProductCard">
|
||||
<div className="addProductH1">Участники мероприятия {currentEvent.name}</div>
|
||||
<Table columns={columns} dataSource={data} />
|
||||
<Button onClick={()=>navigator("/hr")} className="btn2">Назад</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
0
src/hr/regUsers/regUsers.css
Normal file
0
src/hr/regUsers/regUsers.css
Normal file
126
src/hr/transactionHistory/index.tsx
Normal file
126
src/hr/transactionHistory/index.tsx
Normal file
|
@ -0,0 +1,126 @@
|
|||
import { Button, Table, Tag } from "antd";
|
||||
import { ColumnsType } from "antd/es/table";
|
||||
import React, { useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { adminFetcher, hrFetcher, useHRDispatch } from "../../app/hooks";
|
||||
import { Header } from "../../components/Header";
|
||||
|
||||
interface DataTypeIE{
|
||||
key:string,
|
||||
type:string,
|
||||
user_from:string,
|
||||
user_to: string,
|
||||
amount: number
|
||||
}
|
||||
|
||||
export const TransactionHistory: React.FC = () =>{
|
||||
const [transaction, setTransaction] = useState([-1] as any)
|
||||
let location = useLocation()
|
||||
let hr;
|
||||
if (location.pathname.split("/")[1] == "hr"){
|
||||
hr = true
|
||||
}
|
||||
|
||||
if (transaction[0] == -1){
|
||||
if(hr){
|
||||
console.log(1)
|
||||
hrFetcher.get("blockchain/history/").then(response=>setTransaction(response.data))
|
||||
}
|
||||
else{
|
||||
console.log(2)
|
||||
adminFetcher.get("blockchain/history/").then(response=>setTransaction(response.data))
|
||||
|
||||
}
|
||||
}
|
||||
let navigator = useNavigate()
|
||||
const collator = new Intl.Collator('ru');
|
||||
const data:DataTypeIE[] = []
|
||||
|
||||
const columns: ColumnsType<DataTypeIE> = [
|
||||
{
|
||||
title: 'Тип операции',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
sorter: (a, b) => collator.compare(a.type, b.type),
|
||||
render: text=><Tag color="green">
|
||||
{text}
|
||||
</Tag>
|
||||
},
|
||||
{
|
||||
title: 'Отправитель',
|
||||
dataIndex: 'user_from',
|
||||
key: 'user_from',
|
||||
sorter: (a, b) => collator.compare(a.user_from, b.user_from) ,
|
||||
|
||||
},
|
||||
{
|
||||
title: 'Получатель',
|
||||
dataIndex: 'user_to',
|
||||
key: 'user_to',
|
||||
sorter: (a, b) => collator.compare(a.user_to, b.user_to) ,
|
||||
|
||||
},
|
||||
{
|
||||
title: 'Сумма',
|
||||
dataIndex: 'amount',
|
||||
key: 'amount',
|
||||
render: text=><div>{ text} <img src="/rub.svg"></img></div>
|
||||
},
|
||||
]
|
||||
transaction.forEach((el:any)=>{
|
||||
data.push({
|
||||
key: el.type,
|
||||
type: el.type,
|
||||
user_from: el.user_from,
|
||||
user_to: el.user_to,
|
||||
amount: el.amount,
|
||||
} as DataTypeIE)
|
||||
})
|
||||
|
||||
return(
|
||||
<div className="addProduct">
|
||||
{hr? <Header links={[
|
||||
{
|
||||
link:"/hr",
|
||||
name:"События"
|
||||
},
|
||||
{
|
||||
link:"/hr/addEvent",
|
||||
name:"Создать событие"
|
||||
},
|
||||
{
|
||||
link:"/hr/transaction",
|
||||
name:"История транзакций"
|
||||
}
|
||||
]} name={"HR"}></Header>: <Header links={[
|
||||
{
|
||||
link:"/admin/users",
|
||||
name:"Участники"
|
||||
},
|
||||
{
|
||||
link:"/admin/market",
|
||||
name:"Market place"
|
||||
},
|
||||
{
|
||||
link:"/admin/market/add",
|
||||
name:"Cоздать товар (NFT)"
|
||||
},
|
||||
{
|
||||
link:"/admin/transaction",
|
||||
name:"История транзакций"
|
||||
},
|
||||
|
||||
]}
|
||||
name={"Firesieht"}></Header>
|
||||
}
|
||||
|
||||
|
||||
<div className="addProductCard">
|
||||
<div className="addProductH1">История транзакций</div>
|
||||
<Button onClick={()=>navigator("/transaction")} className="btn1">Сделать перевод</Button>
|
||||
<Table columns={columns} dataSource={data} />
|
||||
<Button onClick={()=>navigator(-1)} className="btn2">Назад</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -23,6 +23,12 @@ import { AdminClans } from './admin/adminClans';
|
|||
import { AddUser } from './admin/addUser';
|
||||
import { UserLk } from './user/lk';
|
||||
import { Clan } from './user/clan';
|
||||
import { HR } from './hr';
|
||||
import { hrStore } from './app/hrStore';
|
||||
import { AddEvent } from './hr/addEvent';
|
||||
import { RegUsers } from './hr/regUsers';
|
||||
import { TransactionHistory } from './hr/transactionHistory';
|
||||
import { Transaction } from './Transaction';
|
||||
|
||||
|
||||
const container = document.getElementById('root')!;
|
||||
|
@ -38,10 +44,17 @@ const router = createBrowserRouter(
|
|||
<Route path='admin/users/:tg' element={<Provider store={adminStore}><AdminUserCard></AdminUserCard></Provider>}></Route>
|
||||
<Route path='admin/clans/:id' element={<Provider store={adminStore}><AdminClans></AdminClans></Provider>}></Route>
|
||||
<Route path='admin/users/add' element={<Provider store={adminStore}><AddUser></AddUser></Provider>}></Route>
|
||||
<Route path="/admin/transaction" element={<Provider store={adminStore}><TransactionHistory></TransactionHistory></Provider>}></Route>
|
||||
|
||||
<Route path="hr" element={<Provider store={hrStore}><HR></HR></Provider>}></Route>
|
||||
<Route path="hr/addEvent" element={<Provider store={hrStore}><AddEvent></AddEvent></Provider>}></Route>
|
||||
<Route path="/hr/events/reg/:name" element={<Provider store={hrStore}><RegUsers></RegUsers></Provider>}></Route>
|
||||
<Route path="/hr/transaction" element={<Provider store={hrStore}><TransactionHistory></TransactionHistory></Provider>}></Route>
|
||||
|
||||
<Route path="hr"></Route>
|
||||
<Route path="user/lk/" element={<UserLk />} />
|
||||
<Route path='user/clan' element={<Clan />} />
|
||||
|
||||
<Route path="transaction" element={<Transaction></Transaction>}></Route>
|
||||
</Route>
|
||||
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user