Extract AddPlayers component

This commit is contained in:
Kalle
2022-01-27 17:29:31 +02:00
parent 8b00647eb8
commit 09df17ec87
5 changed files with 144 additions and 113 deletions

View File

@@ -0,0 +1,98 @@
import { Form, useLocation } from "remix";
import { useBaseURL, useTimeoutState } from "~/hooks/common";
import { FindManyByTrustReceiverId } from "~/models/TrustRelationship.server";
import { FormErrorMessage } from "./FormErrorMessage";
import { Label } from "./Label";
import { SubmitButton } from "./SubmitButton";
export function AddPlayers({
inviteCode,
addUserError,
trustingUsers,
hiddenInputs,
}: {
inviteCode: string;
addUserError?: string;
trustingUsers: FindManyByTrustReceiverId;
hiddenInputs: { name: string; value: string }[];
}) {
const baseURL = useBaseURL();
const location = useLocation();
const urlWithInviteCode = `${baseURL}${location.pathname.replace(
"manage-team",
"join-team"
)}?code=${inviteCode}`;
return (
<fieldset className="add-players__actions">
<legend>Add players to your team</legend>
<div className="add-players__actions__section">
<Label htmlFor="inviteCodeInput">Share this URL</Label>
<input
id="inviteCodeInput"
className="add-players__input"
disabled
value={urlWithInviteCode}
/>
<CopyToClipboardButton urlWithInviteCode={urlWithInviteCode} />
</div>
{trustingUsers.length > 0 && (
<div className="add-players__actions__section">
<Form method="post">
{hiddenInputs.map((input) => (
<input
key={input.value}
name={input.name}
value={input.value}
type="hidden"
/>
))}
<Label htmlFor="userId">
Add players you previously played with
</Label>
<select className="add-players__select" name="userId" id="userId">
{trustingUsers.map(({ trustGiver }) => (
<option key={trustGiver.id} value={trustGiver.id}>
{trustGiver.discordName}
</option>
))}
</select>
<FormErrorMessage errorMsg={addUserError} />
<SubmitButton
className="add-players__input__button"
actionType="ADD_PLAYER"
loadingText="Adding..."
data-cy="add-to-roster-button"
>
Add to roster
</SubmitButton>
</Form>
</div>
)}
</fieldset>
);
}
function CopyToClipboardButton({
urlWithInviteCode,
}: {
urlWithInviteCode: string;
}) {
const [showCopied, setShowCopied] = useTimeoutState(false);
return (
<button
className="add-players__input__button"
onClick={() => {
navigator.clipboard
.writeText(urlWithInviteCode)
.then(() => setShowCopied(true))
.catch((e) => console.error(e));
}}
type="button"
data-cy="copy-to-clipboard-button"
>
{showCopied ? "Copied!" : "Copy to clipboard"}
</button>
);
}

View File

@@ -16,6 +16,7 @@ export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: styles }];
};
// TODO: Switch to layout component
export const meta: MetaFunction = () => {
return {
title: makeTitle("Play!"),

View File

@@ -8,12 +8,11 @@ import {
redirect,
useActionData,
useLoaderData,
useLocation,
} from "remix";
import { z } from "zod";
import { AddPlayers } from "~/components/AddPlayers";
import { Alert } from "~/components/Alert";
import { Catcher } from "~/components/Catcher";
import { FormErrorMessage } from "~/components/FormErrorMessage";
import { FormInfoText } from "~/components/FormInfoText";
import { Label } from "~/components/Label";
import { SubmitButton } from "~/components/SubmitButton";
@@ -26,19 +25,18 @@ import {
roompassRegExpString,
tournamentURL,
} from "~/core/tournament/utils";
import { useBaseURL, useTimeoutState } from "~/hooks/common";
import * as Tournament from "~/models/Tournament.server";
import * as TournamentTeam from "~/models/TournamentTeam.server";
import * as TournamentTeamMember from "~/models/TournamentTeamMember.server";
import * as User from "~/models/User.server";
import type { FindManyByTrustReceiverId } from "~/models/TrustRelationship.server";
import styles from "~/styles/tournament-manage-team.css";
import { parseRequestFormData, requireUser, validate } from "~/utils";
import {
isCaptainOfTheTeam,
teamHasNotCheckedIn,
tournamentTeamIsNotFull,
} from "~/core/tournament/validators";
import * as Tournament from "~/models/Tournament.server";
import * as TournamentTeam from "~/models/TournamentTeam.server";
import * as TournamentTeamMember from "~/models/TournamentTeamMember.server";
import type { FindManyByTrustReceiverId } from "~/models/TrustRelationship.server";
import * as User from "~/models/User.server";
import styles from "~/styles/tournament-manage-team.css";
import { parseRequestFormData, requireUser, validate } from "~/utils";
export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: styles }];
@@ -205,13 +203,6 @@ export const loader: LoaderFunction = async ({ params, context }) => {
export default function ManageTeamPage() {
const actionData = useActionData<ActionData>();
const { ownTeam, trustingUsers } = useLoaderData<Data>();
const baseURL = useBaseURL();
const location = useLocation();
const urlWithInviteCode = `${baseURL}${location.pathname.replace(
"manage-team",
"join-team"
)}?code=${ownTeam.inviteCode}`;
return (
<div className="tournament__manage-team">
@@ -301,78 +292,19 @@ export default function ManageTeamPage() {
</fieldset>
</Form>
{ownTeam.members.length < TOURNAMENT_TEAM_ROSTER_MAX_SIZE && (
<fieldset className="tournament__manage-team__actions">
<legend>Add players to your team</legend>
<div className="tournament__manage-team__actions__section">
<Label htmlFor="inviteCodeInput">Share this URL</Label>
<input
id="inviteCodeInput"
className="tournament__manage-team__input"
disabled
value={urlWithInviteCode}
/>
<CopyToClipboardButton urlWithInviteCode={urlWithInviteCode} />
</div>
{trustingUsers.length > 0 && (
<div className="tournament__manage-team__actions__section">
<Form method="post">
<input type="hidden" name="_action" value="ADD_PLAYER" />
<input type="hidden" name="teamId" value={ownTeam.id} />
<Label htmlFor="userId">
Add players you previously played with
</Label>
<select
className="tournament__manage-team__select"
name="userId"
id="userId"
>
{trustingUsers.map(({ trustGiver }) => (
<option key={trustGiver.id} value={trustGiver.id}>
{trustGiver.discordName}
</option>
))}
</select>
<FormErrorMessage errorMsg={actionData?.error?.userId} />
<SubmitButton
className="tournament__manage-team__input__button"
actionType="ADD_PLAYER"
loadingText="Adding..."
data-cy="add-to-roster-button"
>
Add to roster
</SubmitButton>
</Form>
</div>
)}
</fieldset>
<AddPlayers
inviteCode={ownTeam.inviteCode}
trustingUsers={trustingUsers}
hiddenInputs={[
{ name: "_action", value: "ADD_PLAYER" },
{ name: "teamId", value: ownTeam.id },
]}
addUserError={actionData?.error?.userId}
/>
)}
</div>
);
}
function CopyToClipboardButton({
urlWithInviteCode,
}: {
urlWithInviteCode: string;
}) {
const [showCopied, setShowCopied] = useTimeoutState(false);
return (
<button
className="tournament__manage-team__input__button"
onClick={() => {
navigator.clipboard
.writeText(urlWithInviteCode)
.then(() => setShowCopied(true))
.catch((e) => console.error(e));
}}
type="button"
data-cy="copy-to-clipboard-button"
>
{showCopied ? "Copied!" : "Copy to clipboard"}
</button>
);
}
// TODO: handle 404 (logged in but not registered)
export const CatchBoundary = Catcher;

View File

@@ -397,6 +397,34 @@ select::selection {
padding-inline: var(--s-2);
}
.add-players__actions {
display: flex;
width: 100%;
flex-wrap: wrap;
justify-content: center;
column-gap: var(--s-14);
row-gap: var(--s-8);
}
.add-players__actions__section {
display: flex;
width: 18rem;
flex-direction: column;
align-items: flex-start;
}
.add-players__input {
width: min(100%, 20rem);
}
.add-players__input__button {
margin-block-start: var(--s-4);
}
.add-players__select {
width: min(100%, 10rem);
}
/* Utility classes */
.mt-2 {

View File

@@ -9,30 +9,6 @@
margin: 0 auto;
}
.tournament__manage-team__actions {
display: flex;
width: 100%;
flex-wrap: wrap;
justify-content: center;
column-gap: var(--s-14);
row-gap: var(--s-8);
}
.tournament__manage-team__actions__section {
display: flex;
width: 18rem;
flex-direction: column;
align-items: flex-start;
}
.tournament__manage-team__input {
width: min(100%, 20rem);
}
.tournament__manage-team__select {
width: min(100%, 10rem);
}
.tournament__manage-team__radio-with-label {
display: flex;
align-items: center;
@@ -43,7 +19,3 @@
margin-block-end: 0;
margin-inline-start: var(--s-2);
}
.tournament__manage-team__input__button {
margin-block-start: var(--s-4);
}