initial commit
This commit is contained in:
commit
6f5a39c212
47 changed files with 3601 additions and 0 deletions
188
web/src/components/sidebarViews/SidebarAccount.tsx
Normal file
188
web/src/components/sidebarViews/SidebarAccount.tsx
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import toast from 'react-hot-toast';
|
||||
import { useGoogleReCaptcha } from "react-google-recaptcha-v3";
|
||||
import Button from "../../miniComponents/Button";
|
||||
import Input from "../../miniComponents/Input";
|
||||
import { trty } from "../../treaty";
|
||||
|
||||
export default function SidebarAccount({ setSocketUrl, currentView, accountState, setAccountState }) {
|
||||
|
||||
const rerun = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
async function asyncFunc() {
|
||||
const data = (await trty.api.auth.userInfo.get()).data;
|
||||
if (data) {
|
||||
setAccountState(data as { username: string })
|
||||
} else {
|
||||
setAccountState(undefined)
|
||||
}
|
||||
}
|
||||
asyncFunc()
|
||||
}, [rerun])
|
||||
|
||||
|
||||
function AccountSignedIn() {
|
||||
const statusRef = useRef<HTMLInputElement>();
|
||||
|
||||
async function handleLogout() {
|
||||
await trty.api.auth.logout.get();
|
||||
rerun[1](a => !a)
|
||||
}
|
||||
async function uploadImage() {
|
||||
let image_input = document.getElementById("profile_picture_input") as HTMLInputElement
|
||||
if (!image_input) {
|
||||
image_input = document.createElement("input");
|
||||
image_input.style.display = "none";
|
||||
image_input.type = "file"
|
||||
image_input.accept = "image/jpeg, image/png, image/jpg"
|
||||
image_input.id = "profile_picture_input"
|
||||
document.body.appendChild(image_input)
|
||||
|
||||
image_input.addEventListener("change", () => {
|
||||
toast.promise((async () => {
|
||||
await trty.api.profile.setProfilePicture.post({
|
||||
file: image_input.files[0]
|
||||
})
|
||||
})(), {
|
||||
loading: "Uploading..",
|
||||
success: "Uploaded!",
|
||||
error: "Upload failed. :("
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
image_input.click()
|
||||
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-center text-xl text-white ">Signed in as <strong>{accountState.username}</strong></h1>
|
||||
<Button onClick={handleLogout}>Logout</Button>
|
||||
<Button onClick={uploadImage}>
|
||||
<div class="flex items-center text-center">
|
||||
<i class="fa-solid fa-image text-3xl text-slate-500 mr-2"></i>Set a profile picture
|
||||
</div>
|
||||
</Button>
|
||||
<Input placeholder="Set a status!" ref={statusRef}></Input>
|
||||
<Button onClick={() => {
|
||||
toast.promise((async () => {
|
||||
if(statusRef.current.value.trim()) {
|
||||
await trty.api.profile.setStatus.post({
|
||||
status: statusRef.current.value
|
||||
});
|
||||
}
|
||||
})(), {
|
||||
success: "Status set!",
|
||||
loading: "Setting status..",
|
||||
error: "Failed to set status."
|
||||
})
|
||||
}}>Set status</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function AccountSignedOut() {
|
||||
const usernameRef = useRef<HTMLInputElement>();
|
||||
const passwordRef = useRef<HTMLInputElement>();
|
||||
const { executeRecaptcha } = useGoogleReCaptcha();
|
||||
|
||||
async function handleSignIn() {
|
||||
const username = usernameRef.current.value.trim();
|
||||
const password = passwordRef.current.value.trim();
|
||||
if (!username || !password) {
|
||||
toast.error("Missing username or password!", {
|
||||
position: "bottom-right",
|
||||
})
|
||||
return;
|
||||
}
|
||||
const loadingToast = toast.loading("Logging in..", {
|
||||
position: "bottom-right",
|
||||
});
|
||||
const token = await executeRecaptcha("login");
|
||||
const request = await trty.api.auth.login.post({
|
||||
password: password,
|
||||
username: username,
|
||||
recaptcha: token
|
||||
})
|
||||
if (request.status != 200) {
|
||||
toast.error(request.error.value as unknown as string, {
|
||||
position: "bottom-right",
|
||||
});
|
||||
toast.remove(loadingToast);
|
||||
|
||||
return;
|
||||
}
|
||||
toast.success(`You've logged into ${username}!`, {
|
||||
position: "bottom-right",
|
||||
})
|
||||
toast.remove(loadingToast);
|
||||
setSocketUrl(z => z.replace(/\?.*$/gm, "") + "?a=" + Math.random())
|
||||
rerun[1](a => !a)
|
||||
}
|
||||
|
||||
async function handleRegister() {
|
||||
const username = usernameRef.current.value.trim();
|
||||
const password = passwordRef.current.value.trim();
|
||||
if (!username || !password) {
|
||||
toast.error("Missing username or password!", {
|
||||
position: "bottom-right",
|
||||
})
|
||||
return;
|
||||
}
|
||||
const loadingToast = toast.loading("Registering..", {
|
||||
position: "bottom-right",
|
||||
});
|
||||
const token = await executeRecaptcha("register");
|
||||
const request = await trty.api.auth.register.post({
|
||||
password: password,
|
||||
username: username,
|
||||
recaptcha: token
|
||||
})
|
||||
if (request.status != 200) {
|
||||
toast.error(request.error.value as unknown as string, {
|
||||
position: "bottom-right",
|
||||
});
|
||||
toast.remove(loadingToast);
|
||||
|
||||
return;
|
||||
}
|
||||
toast.success(`Your account ${username} has been registered!`, {
|
||||
position: "bottom-right",
|
||||
})
|
||||
toast.remove(loadingToast);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="flex flex-col">
|
||||
<Input placeholder="Username" extraClass="mb-1" type="username" ref={usernameRef}></Input>
|
||||
<Input placeholder="Password" extraClass="mb-1" type="password" ref={passwordRef}></Input>
|
||||
<Button onClick={handleSignIn}>Sign In</Button>
|
||||
<Button onClick={handleRegister}>Register</Button>
|
||||
<div class="text-sm m-2">
|
||||
This site is protected by reCAPTCHA and the Google <a class="text-gray-400" href="https://policies.google.com/privacy">Privacy Policy</a> and <a href="https://policies.google.com/terms" class="text-gray-400">Terms of Service</a> apply.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<h1 class="text-center text-3xl text-white ">Account</h1>
|
||||
{
|
||||
(() => {
|
||||
if (!accountState) {
|
||||
return <AccountSignedOut></AccountSignedOut>
|
||||
} else {
|
||||
return <AccountSignedIn></AccountSignedIn>
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
60
web/src/components/sidebarViews/SidebarRooms.tsx
Normal file
60
web/src/components/sidebarViews/SidebarRooms.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { useRef } from "preact/hooks";
|
||||
import Button from "../../miniComponents/Button";
|
||||
import Input from "../../miniComponents/Input";
|
||||
|
||||
export default function SidebarRooms({ setSendRoomHidden, setRoomName, roomName, currentView, rooms }) {
|
||||
const dialogRef = useRef<HTMLDialogElement>();
|
||||
const roomInputRef = useRef<HTMLInputElement>();
|
||||
const roomIsHiddenRef = useRef<HTMLInputElement>();
|
||||
|
||||
function createRoomDialog() {
|
||||
dialogRef.current.showModal();
|
||||
}
|
||||
|
||||
function createRoom() {
|
||||
const input = roomInputRef.current.value.trim();
|
||||
if (input) {
|
||||
setSendRoomHidden(roomIsHiddenRef.current.checked);
|
||||
localStorage.lastRoom = input;
|
||||
setRoomName(input);
|
||||
dialogRef.current.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<dialog ref={dialogRef} class="bg-slate-400 p-5 rounded-xl">
|
||||
<div class="flex flex-col">
|
||||
<Input ref={roomInputRef} placeholder="My Awsome Room"></Input>
|
||||
<div class="text-center text-white my-2">
|
||||
<Input type="checkbox" extraClasses="mr-2" ref={roomIsHiddenRef}></Input>
|
||||
Is room hidden?
|
||||
</div>
|
||||
<Button onClick={createRoom}>Create room</Button>
|
||||
|
||||
</div>
|
||||
</dialog>
|
||||
<h1 class="text-center text-3xl text-white ">Rooms</h1>
|
||||
<div class="flex flex-col">
|
||||
{
|
||||
rooms ?
|
||||
rooms.map(z => {
|
||||
return <Button onClick={
|
||||
() => {
|
||||
setSendRoomHidden(false);
|
||||
setRoomName(z.name)
|
||||
}
|
||||
} extraClass={roomName == z.name ? "bg-green-200" : "bg-slate-400"}>
|
||||
<div class="text-2xl">{z.name}</div>
|
||||
<div>{z.count} pe{z.count == 1 ? "rson" : "ople"}</div>
|
||||
</Button>
|
||||
}) : <h1 class="text-2xl text-black text-center">Loading..</h1>
|
||||
}
|
||||
<Button onClick={createRoomDialog}>
|
||||
Create your own room
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
63
web/src/components/sidebarViews/SidebarStaff.tsx
Normal file
63
web/src/components/sidebarViews/SidebarStaff.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { useRef, useState } from "preact/hooks";
|
||||
import toast from 'react-hot-toast';
|
||||
import Button from "../../miniComponents/Button";
|
||||
import Input from "../../miniComponents/Input";
|
||||
import { trty } from "../../treaty";
|
||||
|
||||
export default function SidebarStaff({ setCurrentPeopleView, currentView, setUser }) {
|
||||
|
||||
const userIdRef = useRef<HTMLInputElement>();
|
||||
const [punishments, setPunishments] = useState<undefined | any[]>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 class="text-center text-3xl text-white">Staff</h1>
|
||||
|
||||
<div class="border-b-4">
|
||||
<Input placeholder="user ID" extraClass="m-0" ref={userIdRef}></Input>
|
||||
<Button extraClass="m-0 py-2 my-2 w-full" onClick={async () => {
|
||||
const req = await trty.api.staff.punishments.post({
|
||||
userId: userIdRef.current.value
|
||||
})
|
||||
if (req.data) setPunishments(req.data as any);
|
||||
}}>See punishments</Button>
|
||||
<Button extraClass="m-0 py-2 mb-2 w-full" onClick={() => {
|
||||
const bar = document.getElementById("peopleBar");
|
||||
const barButton = document.getElementById("peopleBarButton");
|
||||
if (bar.style.display !== "flex") {
|
||||
bar.style.display = "flex";
|
||||
barButton.className = barButton.className.replace('right-6', "right-64")
|
||||
}
|
||||
|
||||
setCurrentPeopleView("person");
|
||||
setUser({ id: userIdRef.current.value });
|
||||
}}>User actions</Button>
|
||||
</div>
|
||||
|
||||
{punishments === undefined ? "No user searched." : punishments.length == 0 ? "This user has no punishments!" : punishments.map((z, i) => {
|
||||
return <div class={(i == 0 ? "" : "border-t-2") + " text-black"}>
|
||||
<Button extraClass="p-2 m-1" onClick={() => {
|
||||
toast.promise((async () => {
|
||||
await trty.api.staff.invalidatePunishment.post({
|
||||
punishmentId: z.id
|
||||
})
|
||||
})(), {
|
||||
loading: "Invalidating punishment..",
|
||||
success: "Invalidated.",
|
||||
error: "Failed to invalidate!"
|
||||
})
|
||||
}}>Remove punishment</Button>
|
||||
<div><i class={"text-white fa-solid fa-" + (z.type == "ban" ? "hammer-crash" : "comment-slash")}></i> {z.type.toUpperCase()}</div>
|
||||
<div>ID: <strong>{z.id}</strong></div>
|
||||
<div>Reason: <strong>{z.reason}</strong></div>
|
||||
<div>Banned by: <strong>{z.staffId}</strong></div>
|
||||
<div>Time: <strong>{z.time}ms</strong></div>
|
||||
<div>Banned at: <strong>{z.at.toString()}</strong></div>
|
||||
|
||||
</div>
|
||||
})}
|
||||
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue