Skip to content

Commit

Permalink
✨ Edit Team and other tweaks (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
alejsdev authored Apr 18, 2024
1 parent b4a068e commit 5316f60
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 72 deletions.
37 changes: 23 additions & 14 deletions frontend/src/components/Common/ActionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ import {
useDisclosure,
} from "@chakra-ui/react"
import { BsThreeDotsVertical } from "react-icons/bs"
import { FaExchangeAlt, FaTrash } from "react-icons/fa"
import { FaEdit, FaExchangeAlt, FaTrash } from "react-icons/fa"

import type { ItemPublic, TeamPublic, UserPublic } from "../../client"
import EditItem from "../Items/EditItem"
import ChangeRole from "../Teams/ChangeRole"
import EditTeam from "../Teams/EditTeam"
import Remove from "./RemoveAlert"

interface ActionsMenuProps {
userRole?: string
teamId?: string
team?: TeamPublic
type: string
value: ItemPublic | UserPublic | TeamPublic
disabled?: boolean
}

const ActionsMenu = ({
userRole,
teamId,
team,
type,
value,
disabled,
Expand All @@ -43,12 +43,21 @@ const ActionsMenu = ({
variant="unstyled"
/>
<MenuList>
<MenuItem
onClick={changeRoleModal.onOpen}
icon={<FaExchangeAlt fontSize="16px" />}
>
Change Role
</MenuItem>
{type === "User" ? (
<MenuItem
onClick={changeRoleModal.onOpen}
icon={<FaExchangeAlt fontSize="16px" />}
>
Change Role
</MenuItem>
) : (
<MenuItem
onClick={editUserModal.onOpen}
icon={<FaEdit fontSize="16px" />}
>
Edit {type}
</MenuItem>
)}
<MenuItem
onClick={deleteModal.onOpen}
icon={<FaTrash fontSize="16px" />}
Expand All @@ -60,20 +69,20 @@ const ActionsMenu = ({
{type === "User" ? (
<ChangeRole
userRole={userRole}
teamId={teamId}
teamId={team?.id}
user={value as UserPublic}
isOpen={changeRoleModal.isOpen}
onClose={changeRoleModal.onClose}
/>
) : (
<EditItem
item={value as ItemPublic}
<EditTeam
team={value as TeamPublic}
isOpen={editUserModal.isOpen}
onClose={editUserModal.onClose}
/>
)}
<Remove
teamId={teamId}
teamId={team?.id}
type={type}
id={value.id}
isOpen={deleteModal.isOpen}
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/Common/RemoveAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { useForm } from "react-hook-form"
import { type TDataRemoveMemberFromTeam, TeamsService } from "../../client"
import useCustomToast from "../../hooks/useCustomToast"

interface DeleteProps {
teamId?: string
interface RemoveProps {
teamId?: number
type: string
id: number
isOpen: boolean
onClose: () => void
}

const Remove = ({ teamId, type, id, isOpen, onClose }: DeleteProps) => {
const Remove = ({ teamId, type, id, isOpen, onClose }: RemoveProps) => {
const queryClient = useQueryClient()
const showToast = useCustomToast()
const cancelRef = React.useRef<HTMLButtonElement | null>(null)
Expand Down Expand Up @@ -59,7 +59,7 @@ const Remove = ({ teamId, type, id, isOpen, onClose }: DeleteProps) => {
})

const onSubmit = async () => {
mutation.mutate({ teamId: Number(teamId), userId: id })
mutation.mutate({ teamId: teamId!, userId: id })
}

return (
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Teams/ChangeRole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import useCustomToast from "../../hooks/useCustomToast"

interface ChangeRoleProps {
userRole?: string
teamId?: string
teamId?: number
user: UserPublic
isOpen: boolean
onClose: () => void
Expand All @@ -45,7 +45,7 @@ const ChangeRole = ({
const mutation = useMutation({
mutationFn: (data: { newRole: Role }) =>
TeamsService.updateMemberInTeam({
teamId: Number(teamId),
teamId: teamId!,
requestBody: { role: data.newRole },
userId: user.id,
}),
Expand Down
125 changes: 125 additions & 0 deletions frontend/src/components/Teams/EditTeam.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {
Button,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Select,
} from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { type SubmitHandler, useForm } from "react-hook-form"

import {
type ApiError,
type TeamPublic,
type TeamUpdate,
TeamsService,
} from "../../client"
import useCustomToast from "../../hooks/useCustomToast"

interface EditTeamProps {
team?: TeamPublic
isOpen: boolean
onClose: () => void
}

const EditTeam = ({ team, isOpen, onClose }: EditTeamProps) => {
const queryClient = useQueryClient()
const showToast = useCustomToast()
const {
register,
handleSubmit,
reset,
formState: { isSubmitting, errors, isDirty },
} = useForm<TeamUpdate>({
mode: "onBlur",
criteriaMode: "all",
defaultValues: team,
})

const mutation = useMutation({
mutationFn: (data: TeamUpdate) =>
TeamsService.updateTeam({ requestBody: data, teamId: team?.id || 0 }),
onSuccess: () => {
showToast("Success!", "Item updated successfully.", "success")
onClose()
},
onError: (err: ApiError) => {
const errDetail = (err.body as any)?.detail
showToast("Something went wrong.", `${errDetail}`, "error")
},
onSettled: () => {
queryClient.invalidateQueries()
},
})

const onSubmit: SubmitHandler<TeamUpdate> = async (data) => {
mutation.mutate(data)
}

const onCancel = () => {
reset()
onClose()
}

return (
<>
<Modal
isOpen={isOpen}
onClose={onClose}
size={{ base: "sm", md: "md" }}
isCentered
>
<ModalOverlay />
<ModalContent as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalHeader>Edit Team</ModalHeader>
<ModalCloseButton />
<ModalBody pb={6}>
<FormControl isInvalid={!!errors.name}>
<FormLabel htmlFor="name">Title</FormLabel>
<Input
placeholder="Name"
id="name"
{...register("name", {
required: "Name is required",
})}
type="text"
/>
{errors.name && (
<FormErrorMessage>{errors.name.message}</FormErrorMessage>
)}
</FormControl>
<FormControl mt={4}>
<FormLabel htmlFor="status">Pricing Plan</FormLabel>
<Select>
<option value="option1">Team</option>
<option value="option2">Organization</option>
<option value="option3">Enterprise</option>
</Select>
</FormControl>
</ModalBody>
<ModalFooter gap={3}>
<Button onClick={onCancel}>Cancel</Button>
<Button
variant="primary"
type="submit"
isLoading={isSubmitting}
isDisabled={!isDirty}
>
Save
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
)
}

export default EditTeam
12 changes: 6 additions & 6 deletions frontend/src/routes/_layout/teams/$teamId/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ function TeamTableBody() {
const { teamId } = Route.useParams()
const queryClient = useQueryClient()
const currentUser = queryClient.getQueryData<UserPublic>(["currentUser"])
const { data: org } = useSuspenseQuery({
const { data: team } = useSuspenseQuery({
queryKey: ["team", teamId],
queryFn: () => TeamsService.readTeam({ teamId: Number(teamId) }),
})

const currentUserRole = org.user_links.find(
const currentUserRole = team.user_links.find(
({ user }) => user.id === currentUser?.id,
)?.role

return (
<Tbody>
{org.user_links.map(({ role, user }) => (
{team.user_links.map(({ role, user }) => (
<Tr key={user.id}>
<Td color={!user.full_name ? "ui.dim" : "inherit"}>
{user.full_name || "N/A"}
Expand All @@ -73,7 +73,7 @@ function TeamTableBody() {
<Td>
<ActionsMenu
userRole={role}
teamId={teamId}
team={team}
type="User"
value={user}
disabled={
Expand Down Expand Up @@ -136,7 +136,7 @@ function TeamTable() {

function Team() {
const { teamId } = Route.useParams()
const { data: org } = useQuery({
const { data: team } = useQuery({
queryKey: ["team", teamId],
queryFn: () => TeamsService.readTeam({ teamId: Number(teamId) }),
})
Expand All @@ -147,7 +147,7 @@ function Team() {
<Flex flexDir="row" justify="space-between" align="center">
<Flex flexDir="column">
<Heading size="md" textAlign={{ base: "center", md: "left" }}>
{org?.name}
{team?.name}
</Heading>
<Heading size="sm" textTransform="uppercase" my={8}>
Members
Expand Down
Loading

0 comments on commit 5316f60

Please sign in to comment.