Skip to content

Commit

Permalink
Add invite-user dialog/modal button UI (#328)
Browse files Browse the repository at this point in the history
Dialog shows form for users to invite other users
  • Loading branch information
joshua-rdrgz authored Feb 22, 2024
1 parent 4e2e25f commit 0bd162c
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 0 deletions.
2 changes: 2 additions & 0 deletions frontend/shared-components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ExternalLink from "./external-link/external-link"
import * as Form from "./form/form"
import InfoTooltip from "./info-tooltip/info-tooltip"
import Input from "./input/input"
import InviteUserBtn from "./invite-user-btn/invite-user-btn"
import Label from "./label/label"
import Layout from "./layout/layout"
import LinkButton from "./link-button/link-button"
Expand All @@ -29,6 +30,7 @@ export {
FormLevelError,
InfoTooltip,
Input,
InviteUserBtn,
Label,
Layout,
LinkButton,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.triggerBtn {
font-size: var(--size20);
font-weight: bold;
min-width: max-content;
}
27 changes: 27 additions & 0 deletions frontend/shared-components/invite-user-btn/invite-user-btn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import classNames from "classnames"
import { Dialog as D, PrimaryButton } from "../../shared-components"
import styles from "./invite-user-btn.module.css"
import InviteUserForm from "./sub-comps/invite-user-form"

interface InviteUserBtnProps {
btnClassName?: string
}

export default function InviteUserBtn({ btnClassName }: InviteUserBtnProps) {
const { triggerBtn } = styles

return (
<D.Root>
<D.Trigger asChild>
<PrimaryButton className={classNames(btnClassName, triggerBtn)}>Invite User</PrimaryButton>
</D.Trigger>
<D.Content>
<D.Header>
<D.Title>Invite a User</D.Title>
<D.Description>Invite a user to this organization.</D.Description>
</D.Header>
<InviteUserForm />
</D.Content>
</D.Root>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.submitBtn {
font-size: var(--size16);
min-width: max-content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { FieldValues, useForm } from "react-hook-form"
import { z } from "zod"
import { UserRoles } from "../../../models/profile"
import { Form as F, Input, Dialog as D, PrimaryButton } from "../../../shared-components"
import SelectRole from "./select-role"
import styles from "./invite-user-form.module.css"

type UserRolesKeys = keyof typeof UserRoles

type InviteUserSchema = z.infer<typeof inviteUserSchema>
const inviteUserSchema = z.object({
email: z.string().email(),
role: z.enum(Object.keys(UserRoles) as [UserRolesKeys])
})

export default function InviteUserForm() {
const { submitBtn } = styles

const formMethods = useForm<InviteUserSchema>({
resolver: zodResolver(inviteUserSchema),
defaultValues: {
email: "",
role: "NONE"
}
})

const onSubmit = (values: FieldValues) => {
console.log("values: ", values)
}

return (
<F.Root formMethods={formMethods} onSubmit={formMethods.handleSubmit(onSubmit)}>
<F.Field
control={formMethods.control}
name="email"
render={({ field }) => (
<F.Item>
<F.Label>User&apos;s email</F.Label>
<F.Control>
<Input type="text" {...field} />
</F.Control>
<F.Message />
</F.Item>
)}
/>
<F.Field
control={formMethods.control}
name="role"
render={({ field }) => (
<F.Item>
<F.Label>User&apos;s role</F.Label>
<F.Control>
<SelectRole value={field.value} onChange={field.onChange} />
</F.Control>
</F.Item>
)}
/>
<D.Footer>
<PrimaryButton type="submit" className={submitBtn}>
Invite User
</PrimaryButton>
</D.Footer>
</F.Root>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Select as S } from "../../../shared-components"
import { UserRoles } from "../../../models/profile"
import { capitalizeFirstChar } from "../../../helpers"

const userRoles = Object.keys(UserRoles).filter((el) => isNaN(Number(el)))

interface SelectRoleProps {
value: string
onChange(...event: any[]): void
}

export default function SelectRole({ value, onChange }: SelectRoleProps) {
return (
<S.Root value={value} onValueChange={onChange}>
<S.Trigger>
<S.Value placeholder="Pick the user's role" />
</S.Trigger>
<S.Content>
{userRoles.map((role) => (
<S.Item key={role} value={role}>
{capitalizeFirstChar(role.toLowerCase())}
</S.Item>
))}
</S.Content>
</S.Root>
)
}

0 comments on commit 0bd162c

Please sign in to comment.