Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
emielvanseveren committed Sep 28, 2024
1 parent cfd2342 commit 42a8a69
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 189 deletions.
73 changes: 73 additions & 0 deletions packages/web-main/src/components/TeleportPlayerDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Button, Dialog, styled, TextField } from '@takaro/lib-components';
import { FC } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTeleportPlayer } from 'queries/gameserver';

const Container = styled.div`
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: ${({ theme }) => theme.spacing[1]};
`;

interface TeleportPlayerDialogProps {
gameServerId: string;
playerId: string;
open: boolean;
setOpen: (open: boolean) => void;
}

export const TeleportPlayerDialog: FC<TeleportPlayerDialogProps> = ({ gameServerId, playerId, open, setOpen }) => {
const onSuccess = () => {
setOpen(false);
};

return (
<Dialog open={open} onOpenChange={setOpen}>
<Dialog.Content>
<Dialog.Heading>
<strong>Teleport player:</strong>
</Dialog.Heading>
<Dialog.Body>
<TeleportPlayerForm gameServerId={gameServerId} playerId={playerId} onSuccess={onSuccess} />
</Dialog.Body>
</Dialog.Content>
</Dialog>
);
};

interface TeleportPlayerForm {
playerId: string;
gameServerId: string;
onSuccess: () => void;
}
const TeleportPlayerForm: FC<TeleportPlayerForm> = ({ gameServerId, playerId, onSuccess }) => {
const validationSchema = z.object({
x: z.number(),
y: z.number(),
z: z.number(),
});
const { control, handleSubmit } = useForm<z.infer<typeof validationSchema>>({
resolver: zodResolver(validationSchema),
});

const onSubmit: SubmitHandler<z.infer<typeof validationSchema>> = ({ x, y, z }) => {
const { mutate } = useTeleportPlayer();
try {
mutate({ playerId, gameServerId, x, y, z });
onSuccess();
} catch { }

Check failure on line 60 in packages/web-main/src/components/TeleportPlayerDialog.tsx

View workflow job for this annotation

GitHub Actions / Run Prettier and Commit Changes

Empty block statement

Check failure on line 60 in packages/web-main/src/components/TeleportPlayerDialog.tsx

View workflow job for this annotation

GitHub Actions / node-ci (20)

Empty block statement

Check failure on line 60 in packages/web-main/src/components/TeleportPlayerDialog.tsx

View workflow job for this annotation

GitHub Actions / e2e

Empty block statement
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Container>
<TextField type="number" label="X coordinate" name="x" control={control} placeholder="100" />
<TextField type="number" label="Y coordinate" name="y" control={control} placeholder="100" />
<TextField type="number" label="Z coordinate" name="z" control={control} placeholder="100" />
</Container>
<Button type="submit" fullWidth text="Teleport player" />
</form>
);
};
4 changes: 2 additions & 2 deletions packages/web-main/src/queries/gameserver.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ export const useTeleportPlayer = () => {
useMutation<APIOutput, AxiosError<APIOutput>, TeleportPlayerInput>({
mutationFn: async ({ gameServerId, playerId, x, y, z }) =>
(await apiClient.gameserver.gameServerControllerTeleportPlayer(gameServerId, playerId, { x, y, z })).data,
onSuccess: async () => {
enqueueSnackbar('Gameserver shutdown.', { variant: 'default', type: 'info' });
onSuccess: async (_, { x, y, z }) => {
enqueueSnackbar(`Teleported player to (${x},${y},${z})`, { variant: 'default', type: 'info' });
},
}),
{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const VariablesForm: FC<CreateAndUpdateVariableformProps> = ({ variable,
label="Value"
loading={isLoading}
name="value"
placeholder="My cool role"
placeholder="My cool variable"
description="Value is a string. However the most common use case is to store stringified JSON. You can e.g. use https://jsonformatter.org/json-stringify-online to stringify JSON."
required
/>
Expand Down
149 changes: 98 additions & 51 deletions packages/web-main/src/routes/_auth/_global/player.$playerId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
getInitials,
HorizontalNav,
CopyId,
Card,
Tooltip,
} from '@takaro/lib-components';
import { Outlet, redirect, createFileRoute, Link } from '@tanstack/react-router';
Expand All @@ -18,11 +17,11 @@ import { useDocumentTitle } from 'hooks/useDocumentTitle';
import { ErrorBoundary } from 'components/ErrorBoundary';
import { hasPermission } from 'hooks/useHasPermission';
import { userMeQueryOptions } from 'queries/user';
import { PlayerOutputWithRolesDTO } from '@takaro/apiclient';
import { FC } from 'react';
import { GameServerSelect } from 'components/selects';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { gameServerSettingQueryOptions } from 'queries/setting';
import { useQuery } from '@tanstack/react-query';

export const searchSchema = z.object({
gameServerId: z.string().optional().catch(''),
Expand Down Expand Up @@ -69,7 +68,41 @@ function Component() {
gameServerId: search.gameServerId,
},
});
const gameserverId = watch('gameServerId');
const gameServerId = watch('gameServerId');

const { data } = useQuery({
...gameServerSettingQueryOptions('economyEnabled', gameServerId!),
enabled: gameServerId ? true : false,
});
const hasEconomyEnabled = data && data.value === 'true' ? true : false;

const renderEconomyLink = () => {
if (!gameServerId) {
return (
<Tooltip>
<Tooltip.Trigger asChild>
<div style={{ color: theme.colors.textAlt }}>Economy</div>
</Tooltip.Trigger>
<Tooltip.Content>Select gameserver to view page</Tooltip.Content>
</Tooltip>
);
} else if (hasEconomyEnabled) {
return (
<Link to="/player/$playerId/$gameserverId/economy" params={{ playerId, gameserverId: gameServerId! }}>
Economy
</Link>
);
} else {
return (
<Tooltip>
<Tooltip.Trigger asChild>
<div style={{ color: theme.colors.textAlt }}>Economy</div>
</Tooltip.Trigger>
<Tooltip.Content>Economy is disabled on this server.</Tooltip.Content>
</Tooltip>
);
}
};

return (
<Container>
Expand Down Expand Up @@ -122,30 +155,19 @@ function Component() {
<Link to="/player/$playerId/events" params={{ playerId }}>
Events
</Link>
{gameserverId ? (
<Link to="/player/$playerId/$gameserverId/inventory" params={{ playerId, gameserverId }}>
{gameServerId ? (
<Link to="/player/$playerId/$gameserverId/inventory" params={{ playerId, gameserverId: gameServerId }}>
Inventory
</Link>
) : (
<Tooltip>
<Tooltip.Trigger asChild>
<div style={{ color: theme.colors.textAlt }}>Inventory</div>
</Tooltip.Trigger>
<Tooltip.Content>Select gameserver</Tooltip.Content>
</Tooltip>
)}
{gameserverId ? (
<Link to="/player/$playerId/$gameserverId/economy" params={{ playerId, gameserverId }}>
Economy
</Link>
) : (
<Tooltip>
<Tooltip.Trigger asChild>
<div style={{ color: theme.colors.textAlt }}>Economy</div>
</Tooltip.Trigger>
<Tooltip.Content>Select gameserver</Tooltip.Content>
<Tooltip.Content>Select gameserver to view page</Tooltip.Content>
</Tooltip>
)}
{renderEconomyLink()}
</HorizontalNav>
<ErrorBoundary>
<Outlet />
Expand All @@ -154,37 +176,62 @@ function Component() {
);
}

const InfoCard = styled(Card)`
h3 {
color: ${({ theme }) => theme.colors.textAlt};
font-weight: 400;
margin-bottom: ${({ theme }) => theme.spacing['1']};
}
`;
//const InfoCard = styled(Card)`
// h3 {
// color: ${({ theme }) => theme.colors.textAlt};
// font-weight: 400;
//
// margin-bottom: ${({ theme }) => theme.spacing['1']};
// }
//`;
//
//const InfoCardBody = styled.div`
// display: grid;
// grid-template-columns: max-content 1fr;
// gap: ${({ theme }) => theme.spacing['8']};
// grid-row-gap: ${({ theme }) => theme.spacing['0_75']};
//
// span {
// text-transform: capitalize;
// }
//`;

const InfoCardBody = styled.div`
display: grid;
grid-template-columns: max-content 1fr;
gap: ${({ theme }) => theme.spacing['8']};
grid-row-gap: ${({ theme }) => theme.spacing['0_75']};
//const SteamInfoCard: FC<{ player: PlayerOutputWithRolesDTO }> = ({ player }) => {
// return (
// <InfoCard variant="outline" onClick={() => window.open(`https://steamcommunity.com/profiles/${player.steamId}`)}>
// <h3>Steam</h3>
// <InfoCardBody>
// <span>VAC banned</span> {player.steamVacBanned ? 'Yes' : 'No'}
// <span>VAC bans</span> {player.steamNumberOfVACBans ?? 0}
// <span>Days since last ban</span> {player.steamsDaysSinceLastBan ?? 0}
// <span>Community banned</span> {player.steamCommunityBanned ? 'Yes' : 'No'}
// <span>Economy Banned</span> {player.steamEconomyBan ? 'Yes' : 'No'}
// </InfoCardBody>
// </InfoCard>
// );
//};

span {
text-transform: capitalize;
}
`;

const SteamInfoCard: FC<{ player: PlayerOutputWithRolesDTO }> = ({ player }) => {
return (
<InfoCard variant="outline" onClick={() => window.open(`https://steamcommunity.com/profiles/${player.steamId}`)}>
<h3>Steam</h3>
<InfoCardBody>
<span>VAC banned</span> {player.steamVacBanned ? 'Yes' : 'No'}
<span>VAC bans</span> {player.steamNumberOfVACBans ?? 0}
<span>Days since last ban</span> {player.steamsDaysSinceLastBan ?? 0}
<span>Community banned</span> {player.steamCommunityBanned ? 'Yes' : 'No'}
<span>Economy Banned</span> {player.steamEconomyBan ? 'Yes' : 'No'}
</InfoCardBody>
</InfoCard>
);
};
//const IpInfo: FC<{ ipInfo: IpHistoryOutputDTO[] }> = ({ ipInfo }) => {
// if (ipInfo.length === 0) {
// return <p>No records</p>;
// }
//
// return (
// <IpInfoContainer>
// {ipInfo.map((ip) => {
// return (
// <IpInfoLine key={ip + '-info-line'}>
// <Tooltip>
// <Tooltip.Trigger asChild>
// <CountryCodeToEmoji countryCode={ip.country} />
// </Tooltip.Trigger>
// <Tooltip.Content>{ip.country}</Tooltip.Content>
// </Tooltip>
// <span>{DateTime.fromISO(ip.createdAt).toLocaleString(DateTime.DATETIME_MED)}</span>
// <span>{ip.city}</span>
// </IpInfoLine>
// );
// })}
// </IpInfoContainer>
// );
//};
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {
AiOutlineClockCircle as KickIcon,
AiOutlineStop as BanIcon,
AiOutlineUndo as UnbanIcon,
AiOutlineEnvironment as TeleportIcon,
} from 'react-icons/ai';
import { MouseEvent, useState } from 'react';
import { GiveItemDialog } from 'components/GiveItemDialog';
import { KickPlayerDialog } from 'components/KickPlayerDialog';
import { BanPlayerDialog } from 'components/BanPlayerDialog';
import { TeleportPlayerDialog } from 'components/TeleportPlayerDialog';
import { useUnbanPlayerOnGameServer } from 'queries/gameserver';

export const Route = createFileRoute('/_auth/_global/player/$playerId/$gameserverId/inventory')({
Expand All @@ -32,6 +34,7 @@ function Component() {
const [openGiveItemDialog, setOpenGiveItemDialog] = useState(false);
const [openKickPlayerDialog, setOpenKickPlayerDialog] = useState(false);
const [openBanPlayerDialog, setOpenBanPlayerDialog] = useState(false);
const [openTeleportPlayerDialog, setOpenTeleportPlayerDialog] = useState(false);
const { mutate } = useUnbanPlayerOnGameServer();

function handleOnGiveItemClicked(e: MouseEvent) {
Expand All @@ -49,6 +52,11 @@ function Component() {
setOpenBanPlayerDialog(true);
}

function handleOnTeleportPlayerClicked(e: MouseEvent) {
e.stopPropagation();
setOpenTeleportPlayerDialog(true);
}

function unBanPlayerClicked() {

Check failure on line 60 in packages/web-main/src/routes/_auth/_global/player.$playerId/$gameserverId.inventory.tsx

View workflow job for this annotation

GitHub Actions / Run Prettier and Commit Changes

'unBanPlayerClicked' is defined but never used. Allowed unused vars must match /^_/u

Check failure on line 60 in packages/web-main/src/routes/_auth/_global/player.$playerId/$gameserverId.inventory.tsx

View workflow job for this annotation

GitHub Actions / node-ci (20)

'unBanPlayerClicked' is defined but never used. Allowed unused vars must match /^_/u

Check failure on line 60 in packages/web-main/src/routes/_auth/_global/player.$playerId/$gameserverId.inventory.tsx

View workflow job for this annotation

GitHub Actions / e2e

'unBanPlayerClicked' is defined but never used. Allowed unused vars must match /^_/u
mutate({ playerId, gameServerId });
}
Expand All @@ -64,6 +72,12 @@ function Component() {
<Dropdown.Menu>
<Dropdown.Menu.Group>
<Dropdown.Menu.Item icon={<GiveItemIcon />} label="Give item" onClick={handleOnGiveItemClicked} />
{/* teleport player should come on the map page */}
<Dropdown.Menu.Item
icon={<TeleportIcon />}
label="Teleport player"
onClick={handleOnTeleportPlayerClicked}
/>
<Dropdown.Menu.Item icon={<KickIcon />} label="Kick player" onClick={handleOnKickPlayerClicked} />
<Dropdown.Menu.Item icon={<BanIcon />} label="Ban player" onClick={handleOnBanPlayerClicked} />
<Dropdown.Menu.Item icon={<UnbanIcon />} label="Unban player" onClick={handleOnBanPlayerClicked} />
Expand All @@ -90,6 +104,12 @@ function Component() {
open={openBanPlayerDialog}
setOpen={setOpenBanPlayerDialog}
/>
<TeleportPlayerDialog
gameServerId={gameServerId}
playerId={playerId}
open={openTeleportPlayerDialog}
setOpen={setOpenTeleportPlayerDialog}
/>
</Section>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC } from 'react';
import { Tooltip, styled, Skeleton } from '@takaro/lib-components';
import { styled, Skeleton } from '@takaro/lib-components';
import { gameServerQueryOptions } from 'queries/gameserver';
import { GameServerOutputDTO, GameServerOutputDTOTypeEnum, PlayerOnGameserverOutputDTO } from '@takaro/apiclient';
import { useQuery } from '@tanstack/react-query';
Expand Down Expand Up @@ -54,19 +54,16 @@ export const PlayerInventoryTable: FC<IPlayerInventoryProps> = ({ pog }) => {
return (
<Grid>
{pog.inventory.map((item, index) => (
<Tooltip key={'tooltip' + item.name} placement="top">
<Tooltip.Trigger asChild>
<GridItem key={index}>
<ItemIcon
src={serverType ? `/icons/${serverType}/${item.code}.png` : placeholderIcon}
alt={item.name}
onError={(e) => (e.currentTarget.src = placeholderIcon)}
/>
<p>{item.amount}</p>
</GridItem>
</Tooltip.Trigger>
<Tooltip.Content>{item.name}</Tooltip.Content>
</Tooltip>
<GridItem key={index}>
<ItemIcon
src={serverType ? `/icons/${serverType}/${item.code}.png` : placeholderIcon}
alt={item.name}
onError={(e) => (e.currentTarget.src = placeholderIcon)}
/>
<p>
{item.amount}x {item.name}
</p>
</GridItem>
))}
</Grid>
);
Expand Down
Loading

0 comments on commit 42a8a69

Please sign in to comment.