Skip to content

Commit

Permalink
Finish up crew management
Browse files Browse the repository at this point in the history
  • Loading branch information
NotNite committed Nov 28, 2023
1 parent 7a11798 commit bf9276d
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 17 deletions.
158 changes: 154 additions & 4 deletions src/api/crew.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export async function getCrews() {
const token = useAuthStore.getState().key;
if (token == null) return null;

const req = await fetch(
const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/crews`,
{
headers: {
Expand All @@ -16,15 +16,15 @@ export async function getCrews() {
);

if (!req.ok) return null;
const res: SimpleCrewResponse[] = await req.json();
const res: SimpleCrewResponse[] = await req.value.json();
return res;
}

export async function getCrew(id: string) {
const token = useAuthStore.getState().key;
if (token == null) return null;

const req = await fetch(
const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${id}`,
{
headers: {
Expand All @@ -34,7 +34,7 @@ export async function getCrew(id: string) {
);

if (!req.ok) return null;
const res: CrewResponse = await req.json();
const res: CrewResponse = await req.value.json();
return res;
}

Expand Down Expand Up @@ -122,3 +122,153 @@ export async function join(
const res: SimpleCrewResponse = await req.value.json();
return { ok: true, value: res };
}

export async function getInvites(crew: string): Promise<string[]> {
const token = useAuthStore.getState().key;
if (token == null) return [];

const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${crew}/invites`,
{
headers: {
Authorization: token
}
}
);

if (!req.ok) return [];
const res: string[] = await req.value.json();
return res;
}

export async function createInvite(crew: string): Promise<string | null> {
const token = useAuthStore.getState().key;
if (token == null) return null;

const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${crew}/invites`,
{
method: "POST",
headers: {
Authorization: token
}
}
);

if (!req.ok) return null;
return await req.value.text();
}

export async function deleteInvite(
crew: string,
invite: string
): Promise<boolean> {
const token = useAuthStore.getState().key;
if (token == null) return false;

const req = await tryFetch(
`${
import.meta.env.VITE_SLOP_CREW_SERVER
}api/crew/${crew}/invites/${invite}`,
{
method: "DELETE",
headers: {
Authorization: token
}
}
);
return req.ok;
}

export async function demote(
crew: string,
user: string
): Promise<Result<null, string>> {
const token = useAuthStore.getState().key;
if (token == null) {
return {
ok: false,
error: "You must be logged in to demote a user"
};
}

const req = await tryFetch(
`${
import.meta.env.VITE_SLOP_CREW_SERVER
}api/crew/${crew}/demote?id=${user}`,
{
method: "POST",
headers: {
Authorization: token
}
}
);

if (!req.ok) return req;
return { ok: true, value: null };
}

export async function kick(
crew: string,
user: string
): Promise<Result<null, string>> {
const token = useAuthStore.getState().key;
if (token == null) {
return { ok: false, error: "You must be logged in to kick a user" };
}

const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${crew}/kick?id=${user}`,
{
method: "POST",
headers: {
Authorization: token
}
}
);

if (!req.ok) return req;
return { ok: true, value: null };
}

export async function leave(crew: string): Promise<Result<null, string>> {
const token = useAuthStore.getState().key;
if (token == null) {
return { ok: false, error: "You must be logged in to leave a crew" };
}

const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${crew}/leave`,
{
method: "POST",
headers: {
Authorization: token
}
}
);

if (!req.ok) return req;
return { ok: true, value: null };
}

export async function nukeItFromOrbit(
crew: string
): Promise<Result<null, string>> {
const token = useAuthStore.getState().key;
if (token == null) {
return { ok: false, error: "You must be logged in to delete a crew" };
}

const req = await tryFetch(
`${import.meta.env.VITE_SLOP_CREW_SERVER}api/crew/${crew}`,
{
method: "DELETE",
headers: {
Authorization: token
}
}
);

if (!req.ok) return req;
return { ok: true, value: null };
}
8 changes: 6 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import CrewsCreate from "./routes/crews/Create.tsx";
import Crew from "./routes/crews/Crew.tsx";
import CrewSettings from "./routes/crews/CrewSettings.tsx";

import { crewsLoader, crewLoader } from "./routes/loaders.ts";
import {
crewsLoader,
crewLoader,
crewSettingsLoader
} from "./routes/loaders.ts";

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -60,7 +64,7 @@ const router = createBrowserRouter([
},
{
path: "crews/:id/settings",
loader: crewLoader,
loader: crewSettingsLoader,
element: <CrewSettings />
},

Expand Down
44 changes: 35 additions & 9 deletions src/routes/crews/Crew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { CrewMember, CrewResponse } from "../../api/types";
import { useAuthStore } from "../../stores";
import Avatar from "../../components/Avatar";
import { useRequiredAuth } from "../../util";
import { demote, kick, leave, promote } from "../../api/crew";

function MembersActions({
crew,
me,
member
}: {
crew: CrewResponse;
me?: CrewMember;
member: CrewMember;
}) {
Expand All @@ -26,7 +29,8 @@ function MembersActions({
{member.owner ? (
<button
onClick={async () => {
revalidator.revalidate();
const req = await demote(crew.id, member.id);
if (req.ok) revalidator.revalidate();
}}
className="normalWidthButton danger"
>
Expand All @@ -35,25 +39,36 @@ function MembersActions({
) : (
<button
onClick={async () => {
revalidator.revalidate();
const req = await promote(crew.id, member.id);
if (req.ok) revalidator.revalidate();
}}
className="normalWidthButton warning"
>
Promote
</button>
)}

<button onClick={() => {}} className="normalWidthButton danger">
Kick
</button>
{!member.owner && (
<button
onClick={async () => {
const req = await kick(crew.id, member.id);
if (req.ok) revalidator.revalidate();
}}
className="normalWidthButton danger"
>
Kick
</button>
)}
</td>
);
}

function MembersTable({
crew,
me,
members
}: {
crew: CrewResponse;
me?: CrewMember;
members: CrewMember[];
}) {
Expand Down Expand Up @@ -81,7 +96,9 @@ function MembersTable({
)}
</td>

{isOwner && <MembersActions me={me} member={member} />}
{isOwner && (
<MembersActions crew={crew} me={me} member={member} />
)}
</tr>
);
})}
Expand All @@ -97,6 +114,8 @@ function LeaveCrewButton({
crew: CrewResponse;
me?: CrewMember;
}) {
const navigate = useNavigate();

const owners = crew.members.filter((x) => x.owner);

// This is implemented serverside as well
Expand All @@ -114,9 +133,16 @@ function LeaveCrewButton({
}

return (
<div className="tooltipHack" data-tooltip={tooltip} data-placement="right">
<div
className="tooltipHack"
data-tooltip={tooltip === "" ? null : tooltip}
data-placement="right"
>
<button
onClick={() => {}}
onClick={async () => {
const req = await leave(crew.id);
if (req.ok) navigate("/crews");
}}
role="button"
className="normalWidthButton danger"
disabled={!canLeave}
Expand Down Expand Up @@ -162,7 +188,7 @@ function CrewInner({ crew }: { crew: CrewResponse }) {

<section className="smolPadding">
<h2>Members</h2>
<MembersTable me={me} members={members} />
<MembersTable crew={crew} me={me} members={members} />
</section>
</>
);
Expand Down
Loading

0 comments on commit bf9276d

Please sign in to comment.