2022-10-21 03:06:37 -05:00
|
|
|
import { Handlers, PageProps } from "$fresh/server.ts";
|
2022-11-10 16:39:48 -06:00
|
|
|
import { getTeam, getTeamUsers, teamUserStatus } from "@/db/mod.ts";
|
|
|
|
import { type Team, type TeamUserStatus, type User } from "@/types.ts";
|
2022-11-10 11:41:46 -06:00
|
|
|
import { type ContextState } from "@/types.ts";
|
2022-10-21 03:06:37 -05:00
|
|
|
|
2022-11-10 16:39:48 -06:00
|
|
|
interface TeamIndexProps {
|
|
|
|
status: TeamUserStatus;
|
2022-10-21 03:06:37 -05:00
|
|
|
team: Team;
|
|
|
|
users: User[];
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:39:48 -06:00
|
|
|
interface TeamStatusProps {
|
|
|
|
status: TeamUserStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
type TeamPageProps = TeamIndexProps | TeamStatusProps;
|
|
|
|
|
2022-11-10 11:41:46 -06:00
|
|
|
export const handler: Handlers<TeamPageProps, ContextState> = {
|
2022-10-21 03:06:37 -05:00
|
|
|
async GET(request, context) {
|
2022-11-10 11:41:46 -06:00
|
|
|
if (!context.state.user?.id) {
|
|
|
|
// unauthenticated requests may not view teams
|
|
|
|
return await context.renderNotFound();
|
|
|
|
}
|
|
|
|
// TODO: implement this with row-level security?
|
|
|
|
// TODO: do I just use supabase at this point?
|
2022-11-09 16:55:27 -06:00
|
|
|
// TODO: only allow logged-in users to view teams (and most resources!)
|
|
|
|
// TODO: only allow users that are a member of a team to view them
|
|
|
|
// NOTE: maybe teams can be public...?
|
2022-10-21 03:06:37 -05:00
|
|
|
const { id } = context.params;
|
2022-11-10 11:41:46 -06:00
|
|
|
|
2022-10-21 03:06:37 -05:00
|
|
|
console.debug({ request, context });
|
|
|
|
try {
|
2022-11-10 16:39:48 -06:00
|
|
|
const status = await teamUserStatus(context.state.user?.id, id);
|
|
|
|
console.log("Status of this user on team:", status, id);
|
|
|
|
if (!status) {
|
2022-11-10 14:34:27 -06:00
|
|
|
return await context.renderNotFound();
|
2022-11-10 16:39:48 -06:00
|
|
|
} else if (["accepted", "manager", "owner"].includes(status)) {
|
|
|
|
// users that are not a member of a team may not view it
|
|
|
|
const team = await getTeam({ id });
|
|
|
|
const users = await getTeamUsers(team) || [];
|
|
|
|
return await context.render({ team, users, status });
|
|
|
|
} else if (["invited", "left", "removed"].includes(status)) {
|
|
|
|
return await context.render({ status });
|
2022-11-10 14:34:27 -06:00
|
|
|
}
|
2022-11-10 16:39:48 -06:00
|
|
|
return await context.renderNotFound();
|
2022-10-21 03:06:37 -05:00
|
|
|
} catch (e) {
|
|
|
|
console.error(`Error handling team page for ID '${id}'`, e);
|
|
|
|
return await context.renderNotFound();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2022-11-10 16:39:48 -06:00
|
|
|
export default function TeamPage({ data }: PageProps<TeamPageProps>) {
|
|
|
|
if ("users" in data) {
|
|
|
|
return <TeamIndex {...data}></TeamIndex>;
|
|
|
|
} else {
|
|
|
|
return <TeamStatus {...data}></TeamStatus>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function TeamStatus({ status }: TeamStatusProps) {
|
|
|
|
return <>Team status: {status}</>;
|
|
|
|
}
|
|
|
|
|
|
|
|
function TeamIndex(
|
|
|
|
{ team: { id, displayName, createdAt }, users, status }: TeamIndexProps,
|
2022-10-21 03:06:37 -05:00
|
|
|
) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<a href="/dashboard">Back to dashboard</a>
|
|
|
|
<h1>{displayName} - created {createdAt.toLocaleString()}</h1>
|
2022-11-10 16:39:48 -06:00
|
|
|
{/* <h1 class="mt-4">Administrate</h1> */}
|
|
|
|
{["owner", "manager"].includes(status) && <Manage teamId={id} />}
|
2022-10-21 03:06:37 -05:00
|
|
|
<h1 class="mt-4">Team Members</h1>
|
|
|
|
<ul>
|
|
|
|
{users.map((user) => (
|
|
|
|
<li key={user.id}>
|
|
|
|
<a href={`/user/${user.id}`}>
|
|
|
|
{(user.displayName || user.username).trim()}
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
2022-11-10 16:39:48 -06:00
|
|
|
|
|
|
|
function Manage({ teamId }: { teamId: string }) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<h1 class="mt-4">Manage</h1>
|
|
|
|
<section>
|
|
|
|
<h2>Invite User</h2>
|
|
|
|
<form
|
|
|
|
autocomplete="off"
|
|
|
|
method="post"
|
|
|
|
action={`/team/${teamId}/invite`}
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
autocomplete="off"
|
|
|
|
type="text"
|
|
|
|
placeholder="Username"
|
|
|
|
name="inviteUsername"
|
|
|
|
id="inviteUsername"
|
|
|
|
/>
|
|
|
|
<input type="submit" value="Invite" />
|
|
|
|
</form>
|
|
|
|
</section>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|