diff --git a/client/src/components/Form/index.js b/client/src/components/Form/index.js
index 68c5095..2e5ef65 100644
--- a/client/src/components/Form/index.js
+++ b/client/src/components/Form/index.js
@@ -98,3 +98,18 @@ export const SelectOption = styled.option`
outline: none;
`;
+
+export const UnorderedList = styled.ul.attrs(props => ({
+ className: props.className
+}))`
+${tw`
+`}
+`;
+
+export const ListItem = styled.li.attrs(props => ({
+ className: props.className
+}))`
+${tw`
+py-1
+`}
+`;
diff --git a/client/src/components/Tourneys/MediaListTile.js b/client/src/components/Tourneys/MediaListTile.js
new file mode 100644
index 0000000..0d022ab
--- /dev/null
+++ b/client/src/components/Tourneys/MediaListTile.js
@@ -0,0 +1,59 @@
+import styled from 'styled-components';
+import tw from 'twin.macro';
+
+import {
+ FlexContainer
+} from '../base';
+
+import {
+ NormalText
+} from '../Text';
+
+
+import { RiEditCircleFill } from 'react-icons/ri';
+import { FaTrashAlt } from 'react-icons/fa';
+
+const ListTileImage = styled.img`
+width: ${props => props.w || '64px'};
+height: ${props => props.h || '64px'};
+object-fit: scale-down;
+${tw`
+`}
+`;
+
+
+
+const ActionButtonContainer = styled.div`
+${tw`
+p-2
+flex
+justify-center
+items-center
+rounded-md
+shadow-md
+bg-[#922626]
+`}
+
+&:hover {
+filter: brightness(140%);
+cursor: pointer;
+}
+`;
+
+
+export default function ListMediaTile(){
+ return (
+
+
+ 850 x 1332
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/client/src/containers/DashboardPage/LeftSideBar/StyledElements.js b/client/src/containers/DashboardPage/LeftSideBar/StyledElements.js
index a5f8faa..e6fd073 100644
--- a/client/src/containers/DashboardPage/LeftSideBar/StyledElements.js
+++ b/client/src/containers/DashboardPage/LeftSideBar/StyledElements.js
@@ -3,7 +3,7 @@ import tw from 'twin.macro';
export const LeftBarContainer = styled.div`
width: ${props => props.active ? '372px' : '60px'};
-position: absolute;
+position: fixed;
left: 0;
top: 0;
${tw`
diff --git a/client/src/containers/DashboardPage/Tournaments/TourneyFullView.js b/client/src/containers/DashboardPage/Tournaments/TourneyFullView.js
index bfaec80..fc3e411 100644
--- a/client/src/containers/DashboardPage/Tournaments/TourneyFullView.js
+++ b/client/src/containers/DashboardPage/Tournaments/TourneyFullView.js
@@ -112,6 +112,7 @@ export default function TourneyFullView({ tourney }) {
registerTourney({
tourneyId: tourney.id,
userId: auth.userId,
+
}).unwrap(),
{
pending: `Registering to ${tourney.title}`,
diff --git a/client/src/containers/TourneyDashboardPage/LeftSideBar/index.js b/client/src/containers/TourneyDashboardPage/LeftSideBar/index.js
index e82b3d2..c533e94 100644
--- a/client/src/containers/TourneyDashboardPage/LeftSideBar/index.js
+++ b/client/src/containers/TourneyDashboardPage/LeftSideBar/index.js
@@ -51,7 +51,6 @@ export default function LeftSideBar({ menuItems, onChangeMenu, activeMenu }){
return (
-
{ setOpen(!open); }}
pad={ open ? '2rem' : '1rem'}>
diff --git a/client/src/containers/TourneyDashboardPage/MenuItems.js b/client/src/containers/TourneyDashboardPage/MenuItems.js
index f413901..ba58feb 100644
--- a/client/src/containers/TourneyDashboardPage/MenuItems.js
+++ b/client/src/containers/TourneyDashboardPage/MenuItems.js
@@ -12,6 +12,7 @@ import { AiOutlineShareAlt } from 'react-icons/ai';
import { NotFound } from '../NotFoundPage/NotFound.js';
import OverviewPage from './Overview';
+import SettingsPage from './Settings';
import Participants from './Participants';
import Registrations from './Registrations';
import Structure from './Structure';
@@ -26,7 +27,7 @@ export const MenuItems = [
{
'name': 'Settings',
'icon': ,
- 'content':
+ 'content':
},
{
'name': 'Structure',
diff --git a/client/src/containers/TourneyDashboardPage/Overview/index.js b/client/src/containers/TourneyDashboardPage/Overview/index.js
index c4e876c..2b44655 100644
--- a/client/src/containers/TourneyDashboardPage/Overview/index.js
+++ b/client/src/containers/TourneyDashboardPage/Overview/index.js
@@ -1,6 +1,13 @@
import styled from "styled-components";
import tw from "twin.macro";
import { useSelector } from "react-redux";
+import { useParams } from "react-router-dom";
+import BounceLoader from "react-spinners/BounceLoader";
+
+
+import {
+ useGetTourneyQuery
+} from '../../../redux/TourneyApi';
import StatusCard from "./components/StatusCard";
@@ -55,9 +62,17 @@ const StructureTile = ({ stage, matchType, players, status }) => (
);
export default function OverviewPage() {
- const { selectedTourney } = useSelector(
- (state) => state.tourney
- );
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
+
+ if(error){
+ return (
+
+ Server ERROR | 500
+ { console.log(error) }
+
+ )
+ }
return (
@@ -76,7 +91,7 @@ export default function OverviewPage() {
- { selectedTourney.members.length }
+ { tourney.members.length }
Participants
@@ -84,7 +99,7 @@ export default function OverviewPage() {
Checked In
- { selectedTourney.max_players }
+ { tourney.max_players }
Tournament Size
diff --git a/client/src/containers/TourneyDashboardPage/Participants/index.js b/client/src/containers/TourneyDashboardPage/Participants/index.js
index f3df82c..973b981 100644
--- a/client/src/containers/TourneyDashboardPage/Participants/index.js
+++ b/client/src/containers/TourneyDashboardPage/Participants/index.js
@@ -2,6 +2,11 @@ import { useSelector } from "react-redux";
import styled from "styled-components";
import tw from "twin.macro";
+import { useParams } from "react-router-dom";
+import {
+ useGetTourneyQuery
+} from '../../../redux/TourneyApi';
+
import {
NormalText,
@@ -88,7 +93,8 @@ const TRow = styled.tr`
export default function Participants(){
- const { selectedTourney } = useSelector((state) => state.tourney);
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
return (
@@ -160,7 +166,7 @@ export default function Participants(){
- {selectedTourney.members.map((m) => {
+ {!error && tourney.members.map((m) => {
return (
{ m.status }
diff --git a/client/src/containers/TourneyDashboardPage/Placements/index.js b/client/src/containers/TourneyDashboardPage/Placements/index.js
index 3810cf5..35fda4e 100644
--- a/client/src/containers/TourneyDashboardPage/Placements/index.js
+++ b/client/src/containers/TourneyDashboardPage/Placements/index.js
@@ -1,6 +1,11 @@
import styled from 'styled-components';
import tw from 'twin.macro';
+import { useParams } from "react-router-dom";
+import {
+ useGetTourneyQuery
+} from '../../../redux/TourneyApi';
+
import {
NormalText,
BoldText,
@@ -74,6 +79,9 @@ items-center
export default function Placements(){
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
+
return (
diff --git a/client/src/containers/TourneyDashboardPage/Registrations/index.js b/client/src/containers/TourneyDashboardPage/Registrations/index.js
index 822211b..8cba0ff 100644
--- a/client/src/containers/TourneyDashboardPage/Registrations/index.js
+++ b/client/src/containers/TourneyDashboardPage/Registrations/index.js
@@ -2,16 +2,20 @@ import { useSelector } from "react-redux";
import styled from "styled-components";
import tw from "twin.macro";
-import { NormalText, BoldText, Text } from "../../../components/Text";
+import { useParams } from "react-router-dom";
+import { useGetTourneyQuery, useUpdateTourneyMutation } from "../../../redux/TourneyApi";
+import { NormalText, BoldText, Text } from "../../../components/Text";
import { FlexContainer, WrapContainer } from "../../../components/base";
-
import Button, { IconButton } from "../../../components/Button";
+import { Marginer } from '../../../components/Marginer';
import { RiRefreshLine, RiFilter3Fill } from "react-icons/ri";
import { AiOutlineFileDone } from "react-icons/ai";
import { MdOutlineCancel } from "react-icons/md";
+import { toast } from 'react-toastify';
+
const Container = styled.div`
${tw`
w-full
@@ -57,9 +61,11 @@ const Table = styled.table`
box-shadow: 0 5px 10px black;
background-color: black;
text-align: left;
+ table-layout: fixed;
border-radius: 5px;
color: white;
+ overflow: hidden;
`;
const THead = styled.th`
@@ -68,23 +74,68 @@ const THead = styled.th`
letter-spacing: 0.05rem;
font-size: 1rem;
font-weight: 800;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
`;
const TData = styled.td`
padding: 0.7rem 2rem;
font-size: 0.9rem;
font-weight: 600;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
`;
const TRow = styled.tr`
- &:nth-child(event) {
- background-color: #f40b41;
+ &:nth-child(even) {
+ ${tw`bg-red-800/40`}
color: white;
}
`;
+const StatusBadge = ({ status }) => {
+ let bgColor = 'bg-blue-500';
+
+ switch(status){
+ case 'accepted':
+ bgColor = 'bg-green-500'
+ break;
+ case 'rejected':
+ bgColor = 'bg-red-500'
+ break;
+ case 'cancelled':
+ bgColor = 'bg-yellow-500'
+ break;
+ }
+
+ return ;
+};
+
export default function Participants() {
- const { selectedTourney } = useSelector((state) => state.tourney);
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
+ const [updateTourney] = useUpdateTourneyMutation();
+
+ const totalRegistered = tourney.members.length;
+ const totalPending = tourney.members.filter(
+ (m) => m.status === "pending"
+ ).length;
+ const totalAccepted = tourney.members.filter(
+ (m) => m.status === "accepted"
+ ).length;
+ const totalRejected = tourney.members.filter(
+ (m) => m.status === "rejected"
+ ).length;
+ const totalCancelled = tourney.members.filter(
+ (m) => m.status === "cancelled"
+ ).length;
+
return (
@@ -99,31 +150,30 @@ export default function Participants() {
- 1
+ {totalRegistered}
Total
- 1
+ {totalPending}
- Pending
- 1
+ {totalRejected}
- Refused
+ Rejected
- 1
+ {totalAccepted}
Accepted
- 1
+ {totalCancelled}
Cancelled
@@ -136,7 +186,7 @@ export default function Participants() {
List of Registrations
Last Update
- 5/22/2022
+ { tourney.updatedAt.substring(0, 10) }
@@ -156,34 +206,76 @@ export default function Participants() {
Player ID
Reg ID
Registered Date
+ Entry Fee
Actions
- {selectedTourney.members.map((m) => {
- return (
-
- { m.status }
- { m.member_id }
- { m.reg_id}
- N/A
-
-
- }
- >
- }
- >
-
-
-
- );
- })}
+ {!error &&
+ tourney.members.map((m, index) => {
+ return (
+
+
+ {m.member_id}
+ {m.reg_id}
+ {m.registered_date.substring(0, 10)}
+
+ {m.fee_paid ? (
+
+ PAID
+
+ ) : (
+
+ NOT PAID
+
+ )}
+
+
+
+ {
+ if(!m.fee_paid) {
+ toast.error("Player has not paid the registration fee!");
+ return;
+ }
+
+ if(m.status === 'accepted') {
+ toast.error("Player has already been accepted!");
+ return;
+ }
+
+
+
+ let allMembers = [ ...(tourney.members) ];
+ let updatedMember = { ...m };
+ allMembers.splice(index, 1);
+
+ updatedMember.status = 'accepted';
+ allMembers.push(updatedMember);
+
+ toast.promise(updateTourney({ id: tourneyId, members: allMembers }).unwrap(),
+ {
+ pending: 'Approving player registration...',
+ success: 'Approved!',
+ error: 'Couldnt approve!'
+ });
+ }}
+ pad={"0.4rem"}
+ icon={}
+ >
+ }
+ >
+
+
+
+ );
+ })}
+
+
);
}
diff --git a/client/src/containers/TourneyDashboardPage/Settings/BasicSettingsSection.js b/client/src/containers/TourneyDashboardPage/Settings/BasicSettingsSection.js
new file mode 100644
index 0000000..d502482
--- /dev/null
+++ b/client/src/containers/TourneyDashboardPage/Settings/BasicSettingsSection.js
@@ -0,0 +1,8 @@
+import styled from "styled-components";
+import tw from "twin.macro";
+
+export default function BasicSettingsSection(){
+
+ // return
+}
+
diff --git a/client/src/containers/TourneyDashboardPage/Settings/index.js b/client/src/containers/TourneyDashboardPage/Settings/index.js
new file mode 100644
index 0000000..3a1d3f2
--- /dev/null
+++ b/client/src/containers/TourneyDashboardPage/Settings/index.js
@@ -0,0 +1,131 @@
+import styled from 'styled-components';
+import tw from 'twin.macro';
+
+import { useParams } from "react-router-dom";
+import {
+ useGetTourneyQuery
+} from '../../../redux/TourneyApi';
+
+import {
+ Text
+} from '../../../components/Text';
+
+import {
+ FlexContainer
+} from '../../../components/base';
+
+import {
+ Marginer
+} from '../../../components/Marginer';
+
+import Button from '../../../components/Button';
+import ListTileImage from '../../../components/Tourneys/MediaListTile';
+
+import {
+ Input,
+ TextArea,
+ UnorderedList,
+ ListItem
+} from '../../../components/Form';
+
+const Container = styled.div`
+${tw`
+w-full
+`}
+`;
+
+export default function Settings(){
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
+
+ console.log(tourney);
+
+ return (
+
+ Settings
+
+ { tourney.title }
+ Description
+
+
+ Medias / Promotion
+
+ Share photos or a video of/for the tournament. Medias can't exceed 10 photos & 1 video
+
+
+
+
+
+
+
+
+
+
+
+
+ Live link, if it will be broadcasted online
+
+
+
+ Prizes
+
+ Add Prizes here, for winner, runner-ups, or custom achievements like best goal, most goal, etc.
+
+
+
+
+
+
+
+
+
+ Sponsers / Supporters
+
+
+
+
+
+
+
+ Managers
+
+ Add managers so they can manage this tournamnet too
+
+
+ Saroj Rai
+ Ajaya RajBhandari
+
+
+
+
+
+ Location
+
+ Specify where you tournaments will held
+
+
+
+
+ Start Date
+
+ When will the tournament start
+
+
+
+ Registraion End Date
+ Tournament Start Date
+ Tournament End Date
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/client/src/containers/TourneyDashboardPage/Structure/index.js b/client/src/containers/TourneyDashboardPage/Structure/index.js
index 7a468ad..139142b 100644
--- a/client/src/containers/TourneyDashboardPage/Structure/index.js
+++ b/client/src/containers/TourneyDashboardPage/Structure/index.js
@@ -1,6 +1,11 @@
import styled from "styled-components";
import tw from "twin.macro";
+import { useParams } from "react-router-dom";
+import {
+ useGetTourneyQuery
+} from '../../../redux/TourneyApi';
+
import { NormalText, BoldText, Text } from "../../../components/Text";
import { FlexContainer, WrapContainer } from "../../../components/base";
import Button, { IconButton } from "../../../components/Button";
@@ -32,6 +37,9 @@ bg-black
`;
export default function Structure() {
+ const { tourneyId } = useParams();
+ const { data: tourney, error } = useGetTourneyQuery(tourneyId);
+
return (
diff --git a/client/src/containers/TourneyDashboardPage/index.js b/client/src/containers/TourneyDashboardPage/index.js
index f3392b1..c70044c 100644
--- a/client/src/containers/TourneyDashboardPage/index.js
+++ b/client/src/containers/TourneyDashboardPage/index.js
@@ -12,6 +12,11 @@ import {
setActiveMenu,
setSelectedTourney,
} from "../../redux/TourneySlice";
+
+import {
+ useGetTourneyQuery
+} from '../../redux/TourneyApi';
+
import LeftSideBar from "./LeftSideBar";
import { MenuItems } from "./MenuItems.js";
import { FlexContainer } from "../../components/base";
@@ -45,34 +50,14 @@ export default function TourneyDashboardPage() {
const dispatch = useDispatch();
const auth = useSelector((state) => state.auth);
- const { dashboard, selectedTourney, isPending, isError, errorMessages } =
- useSelector((state) => state.tourney);
-
- useEffect(() => {
- dispatch(pending());
- (async () => {
- try {
- const options = {
- method: "GET",
- url: `${config.serverUrl}/api/v1/tourneys/${tourneyId}`,
- headers: {
- "Content-Type": "application/json",
- Authorization: "Bearer " + auth.accessToken,
- },
- };
-
- const response = await axios.request(options);
- dispatch(setSelectedTourney(response.data.tourney));
- } catch (e) {
- if (e.response) dispatch(error(e.response.data.errorList));
- }
- })();
- }, [auth.accessToken, dispatch, tourneyId]);
+ const { data: tourney, isPending, error } = useGetTourneyQuery(tourneyId);
+ const { dashboard } = useSelector((state) => state.tourney);
const renderContent = MenuItems.find(
(menu) => menu.name === dashboard.activeMenu
).content;
+
return (
dispatch(setActiveMenu(menuName))}
/>
- {isError && (
+ {error && (
- {" "}
- ERROR{" "}
+ SERVER ERROR | 500
- {errorMessages.map((err) => {
+ {error?.errorList?.map((err) => {
return (
{err}
@@ -106,12 +90,12 @@ export default function TourneyDashboardPage() {
)}
- {(isPending || !selectedTourney) ? (
+ {(isPending || !tourney) ? (
) : (
- !isError && renderContent
+ !error && renderContent
)}
diff --git a/client/src/redux/TourneyApi.js b/client/src/redux/TourneyApi.js
index 0ea42a5..b3b86e6 100644
--- a/client/src/redux/TourneyApi.js
+++ b/client/src/redux/TourneyApi.js
@@ -25,6 +25,7 @@ export const tourneyApi = createApi({
getTourney: builder.query({
query: (id) => `tourneys/${id}`,
providesTags: (_result, _error, id) => [{ type: "Tourneys", id }],
+ transformResponse: (response, _meta, _arg) => response.status === 'success' ? response.tourney : response.errorList
}),
getTourneys: builder.query({
query: ({ pageQuery = {}, ...query }) => ({
diff --git a/client/src/redux/UserApi.js b/client/src/redux/UserApi.js
index e11341c..d40a600 100644
--- a/client/src/redux/UserApi.js
+++ b/client/src/redux/UserApi.js
@@ -20,7 +20,7 @@ export const userApi = createApi({
getUser: builder.query({
query: (id) => `users/${id}`,
providesTags: (_result, _error, id) => [{ type: "Users", id }],
- transformResponse: (response, meta, arg) => response.status === 'success' ? response.user : response.errorList
+ transformResponse: (response, _meta, _arg) => response.status === 'success' ? response.user : response.errorList
}),
getUsers: builder.query({
query: ({ pageQuery, ...query } = {}) => ({
diff --git a/controllers/tourney/register-tourney.js b/controllers/tourney/register-tourney.js
index 5107402..46c8efc 100644
--- a/controllers/tourney/register-tourney.js
+++ b/controllers/tourney/register-tourney.js
@@ -30,6 +30,7 @@ module.exports = function makeRegisterPlayerTourney(tourneyAccess) {
{
member_id: playerId,
reg_id: rand.generate(),
+ registered_date: new Date(),
status: 'pending',
fee_paid: false
},
diff --git a/data-access/tourney-db/mongo-db/serializer.js b/data-access/tourney-db/mongo-db/serializer.js
index 596f7cb..898770d 100644
--- a/data-access/tourney-db/mongo-db/serializer.js
+++ b/data-access/tourney-db/mongo-db/serializer.js
@@ -16,7 +16,9 @@ const _serializeSingle = (tourney) => {
"live_link": tourney.live_link,
"start_date": tourney.start_date,
"end_date": tourney.end_date,
- "registration_fee": tourney.registration_fee
+ "registration_fee": tourney.registration_fee,
+ "createdAt": tourney.createdAt,
+ "updatedAt": tourney.updatedAt
};
};
diff --git a/models/tourney/tourney-schema.js b/models/tourney/tourney-schema.js
index 90f1180..8250a3d 100644
--- a/models/tourney/tourney-schema.js
+++ b/models/tourney/tourney-schema.js
@@ -14,14 +14,21 @@ const tourneyUpdateSchema = Joi.object().keys({
members: Joi.array().items(Joi.object().keys({
member_id: Joi.objectId().required(),
reg_id: Joi.string().min(6).required(),
-
// status for registration, pending | accepted | rejected
- status: Joi.string().valid('pending', 'accepted', 'rejected').required(),
+ status: Joi.string().valid('pending', 'accepted', 'rejected', 'cancelled').required(),
+ registered_date: Joi.date().required(),
fee_paid: Joi.boolean().required()
})),
managers: Joi.array().items(Joi.objectId()),
- sponserships: Joi.array().items(Joi.objectId()),
+ sponserships: Joi.array().items(Joi.object().keys({
+ name: Joi.string(),
+ description: Joi.string().min(8),
+ logo_url: Joi.string(),
+ website_url: Joi.string(),
+ sponser_value: Joi.number()
+ })),
+
prizes: Joi.array().items(Joi.object().keys({
prize_title: Joi.string().required(),
prize_description: Joi.string().required(),
@@ -30,18 +37,19 @@ const tourneyUpdateSchema = Joi.object().keys({
matches: Joi.array().items(Joi.object().keys({
// match id is ref to match
match_id: Joi.objectId().required(),
-
// match_tourney_id is the match id for this tournmanet,
// for e.g. For tourney Round 1 & Match no. 2, this will be 'M1.2'
match_tourney_id: Joi.string().required(),
-
match_played: Joi.boolean().required(),
})),
+
+ hypes: Joi.array().items(Joi.objectId()),
game: Joi.string(),
max_players: Joi.number(),
location: Joi.string(),
registration_fee: Joi.number(),
live_link: Joi.string(),
+ registration_end_date: Joi.date(),
start_date: Joi.date().min('9-1-2021'),
end_date: Joi.date().greater(Joi.ref('start_date')),