Skip to content

Commit 5316f60

Browse files
authored
✨ Edit Team and other tweaks (#40)
1 parent b4a068e commit 5316f60

File tree

6 files changed

+225
-72
lines changed

6 files changed

+225
-72
lines changed

frontend/src/components/Common/ActionsMenu.tsx

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,24 @@ import {
77
useDisclosure,
88
} from "@chakra-ui/react"
99
import { BsThreeDotsVertical } from "react-icons/bs"
10-
import { FaExchangeAlt, FaTrash } from "react-icons/fa"
10+
import { FaEdit, FaExchangeAlt, FaTrash } from "react-icons/fa"
1111

1212
import type { ItemPublic, TeamPublic, UserPublic } from "../../client"
13-
import EditItem from "../Items/EditItem"
1413
import ChangeRole from "../Teams/ChangeRole"
14+
import EditTeam from "../Teams/EditTeam"
1515
import Remove from "./RemoveAlert"
1616

1717
interface ActionsMenuProps {
1818
userRole?: string
19-
teamId?: string
19+
team?: TeamPublic
2020
type: string
2121
value: ItemPublic | UserPublic | TeamPublic
2222
disabled?: boolean
2323
}
2424

2525
const ActionsMenu = ({
2626
userRole,
27-
teamId,
27+
team,
2828
type,
2929
value,
3030
disabled,
@@ -43,12 +43,21 @@ const ActionsMenu = ({
4343
variant="unstyled"
4444
/>
4545
<MenuList>
46-
<MenuItem
47-
onClick={changeRoleModal.onOpen}
48-
icon={<FaExchangeAlt fontSize="16px" />}
49-
>
50-
Change Role
51-
</MenuItem>
46+
{type === "User" ? (
47+
<MenuItem
48+
onClick={changeRoleModal.onOpen}
49+
icon={<FaExchangeAlt fontSize="16px" />}
50+
>
51+
Change Role
52+
</MenuItem>
53+
) : (
54+
<MenuItem
55+
onClick={editUserModal.onOpen}
56+
icon={<FaEdit fontSize="16px" />}
57+
>
58+
Edit {type}
59+
</MenuItem>
60+
)}
5261
<MenuItem
5362
onClick={deleteModal.onOpen}
5463
icon={<FaTrash fontSize="16px" />}
@@ -60,20 +69,20 @@ const ActionsMenu = ({
6069
{type === "User" ? (
6170
<ChangeRole
6271
userRole={userRole}
63-
teamId={teamId}
72+
teamId={team?.id}
6473
user={value as UserPublic}
6574
isOpen={changeRoleModal.isOpen}
6675
onClose={changeRoleModal.onClose}
6776
/>
6877
) : (
69-
<EditItem
70-
item={value as ItemPublic}
78+
<EditTeam
79+
team={value as TeamPublic}
7180
isOpen={editUserModal.isOpen}
7281
onClose={editUserModal.onClose}
7382
/>
7483
)}
7584
<Remove
76-
teamId={teamId}
85+
teamId={team?.id}
7786
type={type}
7887
id={value.id}
7988
isOpen={deleteModal.isOpen}

frontend/src/components/Common/RemoveAlert.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import { useForm } from "react-hook-form"
1414
import { type TDataRemoveMemberFromTeam, TeamsService } from "../../client"
1515
import useCustomToast from "../../hooks/useCustomToast"
1616

17-
interface DeleteProps {
18-
teamId?: string
17+
interface RemoveProps {
18+
teamId?: number
1919
type: string
2020
id: number
2121
isOpen: boolean
2222
onClose: () => void
2323
}
2424

25-
const Remove = ({ teamId, type, id, isOpen, onClose }: DeleteProps) => {
25+
const Remove = ({ teamId, type, id, isOpen, onClose }: RemoveProps) => {
2626
const queryClient = useQueryClient()
2727
const showToast = useCustomToast()
2828
const cancelRef = React.useRef<HTMLButtonElement | null>(null)
@@ -59,7 +59,7 @@ const Remove = ({ teamId, type, id, isOpen, onClose }: DeleteProps) => {
5959
})
6060

6161
const onSubmit = async () => {
62-
mutation.mutate({ teamId: Number(teamId), userId: id })
62+
mutation.mutate({ teamId: teamId!, userId: id })
6363
}
6464

6565
return (

frontend/src/components/Teams/ChangeRole.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import useCustomToast from "../../hooks/useCustomToast"
2121

2222
interface ChangeRoleProps {
2323
userRole?: string
24-
teamId?: string
24+
teamId?: number
2525
user: UserPublic
2626
isOpen: boolean
2727
onClose: () => void
@@ -45,7 +45,7 @@ const ChangeRole = ({
4545
const mutation = useMutation({
4646
mutationFn: (data: { newRole: Role }) =>
4747
TeamsService.updateMemberInTeam({
48-
teamId: Number(teamId),
48+
teamId: teamId!,
4949
requestBody: { role: data.newRole },
5050
userId: user.id,
5151
}),
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import {
2+
Button,
3+
FormControl,
4+
FormErrorMessage,
5+
FormLabel,
6+
Input,
7+
Modal,
8+
ModalBody,
9+
ModalCloseButton,
10+
ModalContent,
11+
ModalFooter,
12+
ModalHeader,
13+
ModalOverlay,
14+
Select,
15+
} from "@chakra-ui/react"
16+
import { useMutation, useQueryClient } from "@tanstack/react-query"
17+
import { type SubmitHandler, useForm } from "react-hook-form"
18+
19+
import {
20+
type ApiError,
21+
type TeamPublic,
22+
type TeamUpdate,
23+
TeamsService,
24+
} from "../../client"
25+
import useCustomToast from "../../hooks/useCustomToast"
26+
27+
interface EditTeamProps {
28+
team?: TeamPublic
29+
isOpen: boolean
30+
onClose: () => void
31+
}
32+
33+
const EditTeam = ({ team, isOpen, onClose }: EditTeamProps) => {
34+
const queryClient = useQueryClient()
35+
const showToast = useCustomToast()
36+
const {
37+
register,
38+
handleSubmit,
39+
reset,
40+
formState: { isSubmitting, errors, isDirty },
41+
} = useForm<TeamUpdate>({
42+
mode: "onBlur",
43+
criteriaMode: "all",
44+
defaultValues: team,
45+
})
46+
47+
const mutation = useMutation({
48+
mutationFn: (data: TeamUpdate) =>
49+
TeamsService.updateTeam({ requestBody: data, teamId: team?.id || 0 }),
50+
onSuccess: () => {
51+
showToast("Success!", "Item updated successfully.", "success")
52+
onClose()
53+
},
54+
onError: (err: ApiError) => {
55+
const errDetail = (err.body as any)?.detail
56+
showToast("Something went wrong.", `${errDetail}`, "error")
57+
},
58+
onSettled: () => {
59+
queryClient.invalidateQueries()
60+
},
61+
})
62+
63+
const onSubmit: SubmitHandler<TeamUpdate> = async (data) => {
64+
mutation.mutate(data)
65+
}
66+
67+
const onCancel = () => {
68+
reset()
69+
onClose()
70+
}
71+
72+
return (
73+
<>
74+
<Modal
75+
isOpen={isOpen}
76+
onClose={onClose}
77+
size={{ base: "sm", md: "md" }}
78+
isCentered
79+
>
80+
<ModalOverlay />
81+
<ModalContent as="form" onSubmit={handleSubmit(onSubmit)}>
82+
<ModalHeader>Edit Team</ModalHeader>
83+
<ModalCloseButton />
84+
<ModalBody pb={6}>
85+
<FormControl isInvalid={!!errors.name}>
86+
<FormLabel htmlFor="name">Title</FormLabel>
87+
<Input
88+
placeholder="Name"
89+
id="name"
90+
{...register("name", {
91+
required: "Name is required",
92+
})}
93+
type="text"
94+
/>
95+
{errors.name && (
96+
<FormErrorMessage>{errors.name.message}</FormErrorMessage>
97+
)}
98+
</FormControl>
99+
<FormControl mt={4}>
100+
<FormLabel htmlFor="status">Pricing Plan</FormLabel>
101+
<Select>
102+
<option value="option1">Team</option>
103+
<option value="option2">Organization</option>
104+
<option value="option3">Enterprise</option>
105+
</Select>
106+
</FormControl>
107+
</ModalBody>
108+
<ModalFooter gap={3}>
109+
<Button onClick={onCancel}>Cancel</Button>
110+
<Button
111+
variant="primary"
112+
type="submit"
113+
isLoading={isSubmitting}
114+
isDisabled={!isDirty}
115+
>
116+
Save
117+
</Button>
118+
</ModalFooter>
119+
</ModalContent>
120+
</Modal>
121+
</>
122+
)
123+
}
124+
125+
export default EditTeam

frontend/src/routes/_layout/teams/$teamId/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@ function TeamTableBody() {
3737
const { teamId } = Route.useParams()
3838
const queryClient = useQueryClient()
3939
const currentUser = queryClient.getQueryData<UserPublic>(["currentUser"])
40-
const { data: org } = useSuspenseQuery({
40+
const { data: team } = useSuspenseQuery({
4141
queryKey: ["team", teamId],
4242
queryFn: () => TeamsService.readTeam({ teamId: Number(teamId) }),
4343
})
4444

45-
const currentUserRole = org.user_links.find(
45+
const currentUserRole = team.user_links.find(
4646
({ user }) => user.id === currentUser?.id,
4747
)?.role
4848

4949
return (
5050
<Tbody>
51-
{org.user_links.map(({ role, user }) => (
51+
{team.user_links.map(({ role, user }) => (
5252
<Tr key={user.id}>
5353
<Td color={!user.full_name ? "ui.dim" : "inherit"}>
5454
{user.full_name || "N/A"}
@@ -73,7 +73,7 @@ function TeamTableBody() {
7373
<Td>
7474
<ActionsMenu
7575
userRole={role}
76-
teamId={teamId}
76+
team={team}
7777
type="User"
7878
value={user}
7979
disabled={
@@ -136,7 +136,7 @@ function TeamTable() {
136136

137137
function Team() {
138138
const { teamId } = Route.useParams()
139-
const { data: org } = useQuery({
139+
const { data: team } = useQuery({
140140
queryKey: ["team", teamId],
141141
queryFn: () => TeamsService.readTeam({ teamId: Number(teamId) }),
142142
})
@@ -147,7 +147,7 @@ function Team() {
147147
<Flex flexDir="row" justify="space-between" align="center">
148148
<Flex flexDir="column">
149149
<Heading size="md" textAlign={{ base: "center", md: "left" }}>
150-
{org?.name}
150+
{team?.name}
151151
</Heading>
152152
<Heading size="sm" textTransform="uppercase" my={8}>
153153
Members

0 commit comments

Comments
 (0)