Skip to content

Commit

Permalink
feat: more work on the bans page.
Browse files Browse the repository at this point in the history
  • Loading branch information
Shigbeard committed Aug 7, 2024
1 parent 1de6600 commit 0cde78d
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 25 deletions.
16 changes: 14 additions & 2 deletions app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,22 @@ export const Navbar: React.FC<NavbarProps> = (props) => {

const handleAuth = () => {
if (props.user) {
navigate('/auth/logout');
navigate('/dashboard');
return;
}
navigate('/auth/steam');
return
}

const logout = () => {
navigate('/auth/logout');
return;
}

return (
// JSX markup for your component goes here
<ThemeProvider specifiedTheme={theme} themeAction="/action/set-theme">
<nav className={`${clsx(theme)} bg-primary-foreground dark:bg-secondary-foreground border dark:border-secondary-foreground shadow`}>
<nav className={`${clsx(theme)} bg-primary-foreground dark:bg-secondary-foreground border dark:border-secondary-foreground shadow sticky top-0 z-50`}>
<div className='container flex flex-wrap justify-between items-center mx-auto'>
<a href="/" className='flex items-center flex-grow'>
<span className="self-center text-xl font-semibold whitespace-nowrap text-primary dark:text-secondary">
Expand Down Expand Up @@ -114,6 +119,13 @@ export const Navbar: React.FC<NavbarProps> = (props) => {
{props.user ? props.user.nickname : 'Login'}
</button>
</li>
{ props.user && (
<li>
<button onClick={logout} type="button" className='sm:w-full sm:text-left block py-2 pr-4 pl-3 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700'>
Logout
</button>
</li>
)}
</ul>
</div>

Expand Down
121 changes: 100 additions & 21 deletions app/routes/bans.tsx → app/routes/bans/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useLoaderData, defer, Await, type MetaFunction, Link } from "@remix-run/react";
import React, { Suspense } from "react";
import { Suspense, useState } from "react";
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
import { Badge } from "~/components/ui/badge";
import { Separator } from "~/components/ui/separator";
Expand All @@ -10,6 +10,8 @@ import { ThemeProvider } from "remix-themes";
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";
import * as schema from "~/db/sourcebans/schema";
// import { ClientOnly } from "remix-utils/client-only";
// import { ProgressiveClientOnly } from "~/components/ProgressiveClientOnly";


export const meta: MetaFunction = () => {
Expand All @@ -19,7 +21,20 @@ export const meta: MetaFunction = () => {
];
};

const steamidConvert64 = (steamid: string) => {
const baseline = BigInt("76561197960265728");
const splitID = steamid.split(":");
const product = BigInt(splitID[2]) * BigInt(2);
const sum = product + baseline;
return (sum + BigInt(splitID[1])).toString();
}
const steamidConvert32 = (steamid: string) => {
const z = (BigInt(steamid) - BigInt("76561197960265728")) / BigInt(2);
const y = BigInt(steamid) % BigInt(2);
return `STEAM_0:${y.toString()}:${z.toString()}`;
}
export async function loader({ request }: LoaderFunctionArgs) {

const { getTheme } = await themeSessionResolver(request)
const connection = await mysql.createConnection({
host: process.env.SOURCEBANS_DB_HOST,
Expand All @@ -37,11 +52,53 @@ export async function loader({ request }: LoaderFunctionArgs) {
user: schema.sbAdmins.user,
}).from(schema.sbAdmins);
const aliases = await db.select().from(schema.sbBanlog);
const users = [] as {user:string, avatar:string}[];
const sids = [] as string[];
for (const ban of bans) {
if (ban.authid && users.filter(user => user.user == ban.authid).length == 0) {
users.push({user: ban.authid, avatar: ''});
sids.push(steamidConvert64(ban.authid));
}
}
while (sids.length > 0) {
// fetch 100 users at a time
const lsids = sids.filter((sid, index) => index < 50);
let reqstring = ''
lsids.forEach((v,i) => {
if (i == 0) {
reqstring += `${v}`;
} else {
reqstring += `,${v}`;
}
const index = sids.indexOf(v);
sids.splice(index, 1);
});
const response = await fetch(`https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${process.env.STEAM_API_KEY}&steamids=${reqstring}`);
const data = await response.json();
const players = data.response.players;
if (players.length == 0) continue;
for (const player of players) {
const sid = steamidConvert32(player.steamid);
// console.log(`1 - sid ${sid}`);
const user = users.findIndex((user) => user.user == sid);
// console.log(`2 - user ${user}`);
// console.log(`3 - player ${users[user]}`)
if (user !== -1) {
// console.log(`4 - avatar ${player.avatarfull}`)
users[user].avatar = player.avatarfull; // FOR SOME GOD DAMN REASON THIS IS VALID
// console.log(users[user]); // HERE... BUT WHEN I LATER PRINT IT...
}
}

}
// console.log(users); // HERE... IT DOESNT FUCKING SHOW UP
connection.destroy();
return defer({
theme: getTheme(),
bans: bans,
admins: admins,
aliases: aliases,
avatars: users,
});
}

Expand All @@ -67,14 +124,7 @@ export interface BanProps {

export default function Bans() {
const data = useLoaderData<typeof loader>();
const [clickedRow, setClickedRow] = React.useState<BanProps | null>(null);
const steamidConvert = (steamid: string) => {
const baseline = BigInt("76561197960265728");
const splitID = steamid.split(":");
const product = BigInt(splitID[2]) * BigInt(2);
const sum = product + baseline;
return (sum + BigInt(splitID[1])).toString();
}
const [clickedRow, setClickedRow] = useState<BanProps | null>(null);
const handleRowClick = (ban: BanProps) => {
return () => {
setClickedRow(ban);
Expand Down Expand Up @@ -124,8 +174,12 @@ export default function Bans() {
<Suspense>
<Await resolve={data.bans as BanProps[]}>
{data.bans.length > 0 && data.bans.map((ban, index) => (
<TableRow key={ban.bid} onClick={handleRowClick(ban)} className={`cursor-pointer ${index % 2 === 0 ? 'bg-muted' : 'bg-background'} hover:bg-primary-foreground`}>
<TableCell className="text-primary">{timestampToDateTime(ban.created)}</TableCell>
<TableRow key={ban.bid} onClick={handleRowClick(ban)} className={`cursor-pointer ${clickedRow && ban == clickedRow ? 'bg-yellow-200 hover:bg-yellow-100' : index % 2 === 0 ? 'bg-muted hover:bg-primary-foreground' : 'bg-background hover:bg-primary-foreground'} `}>
<TableCell className="text-primary">
<Suspense fallback="Loading...">
{timestampToDateTime(ban.created)}
</Suspense>
</TableCell>
<TableCell className="text-primary">{ban.name}</TableCell>
<TableCell className={`${
ban.removeType === null && ban.length > 0 ? 'text-yellow-500' :
Expand All @@ -144,15 +198,20 @@ export default function Bans() {
</div>
{clickedRow && (
<div className="w-[300px] bg-muted rounded-lg p-4 sticky top-14 h-min">
<div className="flex items-center gap-2 mb-4">
<Avatar>
<AvatarImage src='https://via.placeholder.com/200' alt='Player Avatar'/>
<AvatarFallback>{clickedRow.name.charAt(0).toUpperCase()}</AvatarFallback>
<div className="ban-card-grid items-center gap-2 mb-4">
<Avatar className="inline-block w-18 h-18 col-span-1 row-span-1">
<AvatarImage src={data.avatars.filter(a => a.user == clickedRow.authid)[0].avatar ?? 'https://via.placeholder.com/200'} alt='Player Avatar'/>
<AvatarFallback className="bg-muted-foreground">{clickedRow.name.charAt(0).toUpperCase()}</AvatarFallback>
</Avatar>
<div>
<div className="text-primary font-bold text-lg"><Link to={`https://steamcommunity.com/profiles/${steamidConvert(clickedRow.authid)}`} target="_blank" rel="noreferrer">{clickedRow.name}</Link></div>
<div className="text-xs text-muted-foreground">Banned by {data.admins.filter(admin => admin.aid == clickedRow.aid)[0].user}</div>
{clickedRow.removedBy && (<div className="text-xs text-muted-foreground">Unbanned by {data.admins.filter(admin => admin.aid == clickedRow.removedBy)[0].user}</div>)}
<div className="inline-block col-start-2 row-start-1">
<div className="text-primary font-bold text-lg inline-block text-ellipsis text-nowrap w-full"><Link to={`https://steamcommunity.com/profiles/${steamidConvert64(clickedRow.authid)}`} target="_blank" rel="noreferrer" className="inline-block overflow-hidden text-ellipsis text-nowrap w-[100%]">{clickedRow.name}</Link></div>
<div className="text-xs text-muted-foreground">{clickedRow.authid}</div>
</div>
<div className="inline-block w-[80%] col-start-1 col-end-3 row-start-2 row-end-2 px-4">
<ul className="list-disc">
<li className="text-xs text-muted-foreground">Banned by {data.admins.filter(admin => admin.aid == clickedRow.aid)[0].user}</li>
{clickedRow.removedBy && (<li className="text-xs text-muted-foreground">Unbanned by {data.admins.filter(admin => admin.aid == clickedRow.removedBy)[0].user}</li>)}
</ul>
</div>
</div>
<Separator className="my-4"/>
Expand Down Expand Up @@ -184,8 +243,8 @@ export default function Bans() {
<div>
<div className="text-secondary-foreground text-sm font-medium">Aliases:</div>
<div className="text-secondary flex flex-wrap gap-2">
{data.aliases.filter(alias => alias.bid == clickedRow.bid).filter((alias, index, self) => index === self.findIndex((a) => a.name === alias.name)).map(alias => (
<Badge key={alias.sid} variant='outline'>{alias.name}</Badge>
{data.aliases.filter(alias => alias.bid == clickedRow.bid).filter((alias, index, self) => index === self.findIndex((a) => a.name === alias.name)).map((alias,index) => (
<Badge key={index} variant='outline'>{alias.name}</Badge>
))}
{/* <Badge variant='outline'>Alias1</Badge>
<Badge variant='outline'>Alias2</Badge> */}
Expand All @@ -194,6 +253,26 @@ export default function Bans() {
)}
</div>
</div>
) || (
<div className="w-[300px] bg-muted rounded-lg p-4 sticky top-14 h-min">
<div className="flex items-center gap-2 mb-4">
<Avatar>
{/* <AvatarImage src='https://via.placeholder.com/200' alt='Player Avatar'/>
<AvatarFallback>...</AvatarFallback> */}
</Avatar>
<div>
<div className="text-primary font-bold text-lg">

Select a Ban

</div>
<div className="text-xs text-muted-foreground">
to view more details
</div>
</div>
</div>

</div>
)}
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions app/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
}
}

.ban-card-grid {
display: grid;
grid-template: "a a" 100% "b c" 100% / 1fr 4fr;
}

.server-placeholder {
font-size: 0 !important;
line-height: 0 !important;
Expand Down
99 changes: 99 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@remix-run/node": "2.11.0",
"@remix-run/react": "2.11.0",
"@remix-run/serve": "2.11.0",
"@tanstack/react-table": "^8.20.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"drizzle-orm": "^0.32.2",
Expand All @@ -30,6 +31,7 @@
"remix-auth": "^3.7.0",
"remix-auth-steam": "^1.0.4",
"remix-themes": "^1.5.0",
"remix-utils": "^7.6.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7"
},
Expand Down
11 changes: 11 additions & 0 deletions sly.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://sly-cli.fly.dev/registry/config.json",
"libraries": [
{
"name": "jacobparis/ui",
"directory": "./app/components",
"postinstall": [],
"transformers": []
}
]
}
Loading

0 comments on commit 0cde78d

Please sign in to comment.