Fix some type errors

This commit is contained in:
Joe Au-Yeung 2022-10-27 12:58:44 -04:00
commit 20488b35c8
4 changed files with 34 additions and 66 deletions

View File

@ -1341,5 +1341,7 @@
"yearly": "Yearly", "yearly": "Yearly",
"checkout": "Checkout", "checkout": "Checkout",
"your_team_disbanded_successfully": "Your team has been disbanded successfully", "your_team_disbanded_successfully": "Your team has been disbanded successfully",
"error_creating_team": "Error creating team" "error_creating_team": "Error creating team",
"you": "You",
"send_email": "Send email"
} }

View File

@ -14,7 +14,6 @@ import { NewTeamFormValues, PendingMember } from "../lib/types";
type MemberInvitationModalProps = { type MemberInvitationModalProps = {
isOpen: boolean; isOpen: boolean;
currentMember?: MembershipRole;
onExit: () => void; onExit: () => void;
onSubmit: (values: NewMemberForm) => void; onSubmit: (values: NewMemberForm) => void;
}; };
@ -31,55 +30,17 @@ export interface NewMemberForm {
} }
export default function MemberInvitationModal(props: MemberInvitationModalProps) { export default function MemberInvitationModal(props: MemberInvitationModalProps) {
const [errorMessage, setErrorMessage] = useState(""); const { t } = useLocale();
const { t, i18n } = useLocale();
const utils = trpc.useContext();
const _options: MembershipRoleOption[] = [ const options: MembershipRoleOption[] = useMemo(() => {
{ value: "MEMBER", label: t("member") }, return [
{ value: "ADMIN", label: t("admin") }, { value: "MEMBER", label: t("member") },
{ value: "OWNER", label: t("owner") }, { value: "ADMIN", label: t("admin") },
]; { value: "OWNER", label: t("owner") },
];
const newMemberFormMethods = useForm<NewMemberForm>();
const options = useMemo(() => {
_options.forEach((option, i) => {
_options[i].label = t(option.value.toLowerCase());
});
return _options;
}, [t]); }, [t]);
const inviteMemberMutation = trpc.useMutation("viewer.teams.inviteMember", { const newMemberFormMethods = useForm<NewMemberForm>();
async onSuccess() {
await utils.invalidateQueries(["viewer.teams.get"]);
props.onExit();
},
async onError(err) {
setErrorMessage(err.message);
},
});
function inviteMember(e: SyntheticEvent) {
e.preventDefault();
if (!props.team) return;
const target = e.target as typeof e.target & {
elements: {
role: { value: MembershipRole };
inviteUser: { value: string };
sendInviteEmail: { checked: boolean };
};
};
inviteMemberMutation.mutate({
teamId: props.team.id,
language: i18n.language,
role: target.elements["role"].value,
usernameOrEmail: target.elements["inviteUser"].value,
sendEmailInvitation: target.elements["sendInviteEmail"].checked,
});
}
return ( return (
<Dialog open={props.isOpen} onOpenChange={props.onExit}> <Dialog open={props.isOpen} onOpenChange={props.onExit}>
@ -93,11 +54,12 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
your subscription once this member accepts your invite. your subscription once this member accepts your invite.
</span> </span>
}> }>
<form> <Form form={newMemberFormMethods} handleSubmit={(values) => props.onSubmit(values)}>
<div className="space-y-4"> <div className="space-y-4">
<Controller <Controller
name="emailOrUsername" name="emailOrUsername"
control={newMemberFormMethods.control} control={newMemberFormMethods.control}
rules={{ required: true, minLength: 1 }}
render={({ field: { onChange } }) => ( render={({ field: { onChange } }) => (
<TextField <TextField
label={t("email_or_username")} label={t("email_or_username")}
@ -112,6 +74,7 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
<Controller <Controller
name="role" name="role"
control={newMemberFormMethods.control} control={newMemberFormMethods.control}
defaultValue={options[0]}
render={({ field: { onChange } }) => ( render={({ field: { onChange } }) => (
<div> <div>
<label <label
@ -121,7 +84,7 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
</label> </label>
<Select <Select
defaultValue={options[0]} defaultValue={options[0]}
options={props.currentMember !== MembershipRole.OWNER ? options.slice(0, 2) : options} options={options.slice(0, 2)}
id="role" id="role"
name="role" name="role"
className="mt-1 block w-full rounded-sm border-gray-300 text-sm" className="mt-1 block w-full rounded-sm border-gray-300 text-sm"
@ -133,6 +96,7 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
<Controller <Controller
name="sendInviteEmail" name="sendInviteEmail"
control={newMemberFormMethods.control} control={newMemberFormMethods.control}
defaultValue={false}
render={() => ( render={() => (
<div className="relative flex items-start"> <div className="relative flex items-start">
<CheckboxField <CheckboxField
@ -143,25 +107,20 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
)} )}
/> />
</div> </div>
{errorMessage && (
<p className="text-sm text-red-700">
<span className="font-bold">Error: </span>
{errorMessage}
</p>
)}
<DialogFooter> <DialogFooter>
<Button type="button" color="secondary" onClick={props.onExit}> <Button type="button" color="secondary" onClick={props.onExit}>
{t("cancel")} {t("cancel")}
</Button> </Button>
<Button <Button
onClick={() => props.onSubmit(newMemberFormMethods.getValues())} // onClick={() => props.onSubmit(newMemberFormMethods.getValues())}
type="submit"
color="primary" color="primary"
className="ltr:ml-2 rtl:mr-2" className="ltr:ml-2 rtl:mr-2"
data-testid="invite-new-member-button"> data-testid="invite-new-member-button">
{t("invite")} {t("invite")}
</Button> </Button>
</DialogFooter> </DialogFooter>
</form> </Form>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); );

View File

@ -39,6 +39,7 @@ const AddNewTeamMembers = () => {
enabled: false, enabled: false,
onSuccess: (newMember: PendingMember) => { onSuccess: (newMember: PendingMember) => {
membersFieldArray.append(newMember); membersFieldArray.append(newMember);
setSkeletonMember(false);
}, },
}); });
@ -72,6 +73,11 @@ const AddNewTeamMembers = () => {
setSkeletonMember(true); setSkeletonMember(true);
}; };
const handleDeleteMember = (email: string) => {
const memberIndex = formMethods.getValues("members").findIndex((member) => member.email === email);
membersFieldArray.remove(memberIndex);
};
// if (isLoading) return <AddNewTeamMemberSkeleton />; // if (isLoading) return <AddNewTeamMemberSkeleton />;
return ( return (
@ -107,12 +113,13 @@ const AddNewTeamMembers = () => {
/> />
<div> <div>
<div className="flex space-x-1"> <div className="flex space-x-1">
<p>{member?.name || t("team_member")}</p> <p>{member?.name || member?.email || t("team_member")}</p>
{/* Assume that the first member of the team is the creator */} {/* Assume that the first member of the team is the creator */}
{index === 0 && <Badge variant="green">{t("you")}</Badge>}{" "} {index === 0 && <Badge variant="green">{t("you")}</Badge>}
{member.role !== "OWNER" && <Badge variant="orange">{t("pending")}</Badge>} {member.role !== "OWNER" && <Badge variant="orange">{t("pending")}</Badge>}
{member.role === "MEMBER" && <Badge variant="gray">{t("member")}</Badge>} {member.role === "MEMBER" && <Badge variant="gray">{t("member")}</Badge>}
{member.role === "ADMIN" && <Badge variant="default">{t("admin")}</Badge>} {member.role === "ADMIN" && <Badge variant="default">{t("admin")}</Badge>}
{member.sendInviteEmail && <Badge variant="blue">{t("send_email")}</Badge>}
</div> </div>
{member.username ? ( {member.username ? (
<p className="text-gray-600">{`${WEBAPP_URL}/${member?.username}`}</p> <p className="text-gray-600">{`${WEBAPP_URL}/${member?.username}`}</p>
@ -127,7 +134,7 @@ const AddNewTeamMembers = () => {
size="icon" size="icon"
color="secondary" color="secondary"
className="h-[36px] w-[36px]" className="h-[36px] w-[36px]"
onClick={() => removeMemberMutation.mutate({ teamId, memberId: member.id })} onClick={() => handleDeleteMember(member.email)}
/> />
)} )}
</li> </li>

View File

@ -1,13 +1,13 @@
export interface NewTeamFormValues { export interface NewTeamMembersFieldArray {
members: PendingMember[];
}
export interface NewTeamFormValues extends NewTeamMembersFieldArray {
name: string; name: string;
slug: string; slug: string;
avatar: string; avatar: string;
} }
export interface NewTeamMembersFieldArray {
members: PendingMember[];
}
export interface PendingMember { export interface PendingMember {
name: string | null; name: string | null;
email: string; email: string;