Skip to content

Commit 4ab587b

Browse files
authored
♻️ Add CustomCard component for reusable card layout (#243)
1 parent bff0561 commit 4ab587b

File tree

13 files changed

+224
-231
lines changed

13 files changed

+224
-231
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
Box,
3+
type BoxProps,
4+
Divider,
5+
Text,
6+
useColorModeValue,
7+
} from "@chakra-ui/react"
8+
import type React from "react"
9+
10+
interface CustomCardProps extends BoxProps {
11+
title?: string
12+
children: React.ReactNode
13+
}
14+
15+
const CustomCard = ({ title, children, ...props }: CustomCardProps) => {
16+
const borderColor = useColorModeValue("#e4e5eb", "#2a2a2a")
17+
18+
return (
19+
<Box
20+
border={`1px solid ${borderColor}`}
21+
borderRadius="md"
22+
px={8}
23+
py={4}
24+
mb={8}
25+
{...props}
26+
>
27+
<Text fontWeight="bold" mb={4}>
28+
{title}
29+
</Text>
30+
{title && <Divider mb={4} />}
31+
{children}
32+
</Box>
33+
)
34+
}
35+
36+
export default CustomCard

frontend/src/components/Common/EditableField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const EditableField = ({
3131
reset,
3232
formState: { isSubmitting, errors, isDirty, isValid },
3333
} = useForm({
34-
mode: "onBlur",
34+
mode: "all",
3535
criteriaMode: "all",
3636
defaultValues: {
3737
[type]: value,

frontend/src/components/TeamSettings/Billing.tsx

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
Flex,
66
FormControl,
77
FormLabel,
8-
Heading,
98
Skeleton,
109
Table,
1110
TableContainer,
@@ -22,6 +21,7 @@ import { FaFileDownload } from "react-icons/fa"
2221

2322
import CurrentPlan from "../Billing/CurrentPlan"
2423
import PaymentMethod from "../Billing/PaymentMethod"
24+
import CustomCard from "../Common/CustomCard"
2525
import { billings } from "./Billings"
2626

2727
function BillingTableBody() {
@@ -99,36 +99,24 @@ function BillingTable() {
9999

100100
const Billing = () => {
101101
return (
102-
<Container maxW="full" m={4}>
103-
<Heading size="sm">Billing Information</Heading>
104-
<Text py={2} mb={4}>
105-
See information regarding your current plan.
106-
</Text>
107-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
108-
<Box my={4}>
109-
<FormControl id="email">
110-
<FormLabel fontWeight="bold">Billing Email</FormLabel>
111-
<Text>[email protected]</Text>
112-
</FormControl>
113-
</Box>
114-
</Box>
115-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
116-
<Box my={4}>
117-
<Text fontWeight="bold">Current Plan</Text>
118-
<Flex pt={4}>
119-
<CurrentPlan />
120-
<PaymentMethod />
121-
</Flex>
122-
</Box>
123-
</Box>
124-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
125-
<Box my={4}>
126-
<Text fontWeight="bold" pt={4}>
127-
Invoice History
128-
</Text>
129-
<BillingTable />
130-
</Box>
131-
</Box>
102+
<Container maxW="full" my={4} p={0}>
103+
<CustomCard title="Billing Email">
104+
<FormControl id="email">
105+
<FormLabel fontWeight="bold" fontSize="sm" srOnly>
106+
Billing Email
107+
</FormLabel>
108+
<Text>[email protected]</Text>
109+
</FormControl>
110+
</CustomCard>
111+
<CustomCard title="Current Plan">
112+
<Flex p={4} flexDir={{ base: "column", md: "row" }} gap={4}>
113+
<CurrentPlan />
114+
<PaymentMethod />
115+
</Flex>
116+
</CustomCard>
117+
<CustomCard title="Invoice History">
118+
<BillingTable />
119+
</CustomCard>
132120
</Container>
133121
)
134122
}

frontend/src/components/TeamSettings/TeamInformation.tsx

Lines changed: 23 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, Container, Flex, Heading, Text } from "@chakra-ui/react"
1+
import { Box, Container, Flex, Text } from "@chakra-ui/react"
22
import {
33
useMutation,
44
useQueryClient,
@@ -10,6 +10,7 @@ import { useCurrentUser } from "../../hooks/useAuth"
1010
import useCustomToast from "../../hooks/useCustomToast"
1111
import { Route } from "../../routes/_layout/$team"
1212
import { getCurrentUserRole, handleError } from "../../utils"
13+
import CustomCard from "../Common/CustomCard"
1314
import EditableField from "../Common/EditableField"
1415
import Invitations from "../Invitations/Invitations"
1516
import NewInvitation from "../Invitations/NewInvitation"
@@ -41,56 +42,22 @@ const TeamInformation = () => {
4142
})
4243

4344
return (
44-
<Container maxW="full" m={4}>
45-
<Heading size="sm">Team Information</Heading>
46-
<Text py={2} mb={4}>
47-
See information regarding your team.
48-
</Text>
49-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
50-
<Box my={4}>
51-
<Text fontWeight="bold" mb={4}>
52-
Team Name
53-
</Text>
54-
55-
<Flex>
56-
<EditableField
57-
type="name"
58-
value={team.name}
59-
onSubmit={(newName) => mutation.mutate({ name: newName })}
60-
canEdit={currentUserRole === "admin"}
61-
/>
62-
</Flex>
63-
</Box>
64-
</Box>
65-
<Box>
66-
<Box
67-
boxShadow="xs"
68-
px={8}
69-
py={4}
70-
borderRadius="lg"
71-
mb={8}
72-
data-testid="team-members"
73-
>
74-
<Text fontWeight="bold" mb={4}>
75-
Team Members
76-
</Text>
77-
<Team />
78-
</Box>
79-
</Box>
45+
<Container maxW="full" my={4} p={0}>
46+
<CustomCard title="Team Name">
47+
<EditableField
48+
type="name"
49+
value={team.name}
50+
onSubmit={(newName) => mutation.mutate({ name: newName })}
51+
canEdit={currentUserRole === "admin"}
52+
/>
53+
</CustomCard>
54+
<CustomCard title="Team Members" data-testid="team-members">
55+
<Team />
56+
</CustomCard>
8057
{currentUserRole === "admin" && (
8158
<>
82-
<Flex gap="8">
83-
<Box width="70%">
84-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
85-
<Text fontWeight="bold" mb={4}>
86-
Team Invitations
87-
</Text>
88-
<Flex>
89-
<Invitations />
90-
</Flex>
91-
</Box>
92-
</Box>
93-
59+
<CustomCard title="Team Invitations">
60+
<Invitations />
9461
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
9562
<Text fontWeight="bold" mb={4}>
9663
New Invitation
@@ -99,25 +66,15 @@ const TeamInformation = () => {
9966
<NewInvitation />
10067
</Flex>
10168
</Box>
102-
</Flex>
69+
</CustomCard>
10370

104-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
105-
<Text fontWeight="bold" mb={4}>
106-
Transfer Ownership
107-
</Text>
108-
<Flex>
109-
<TransferTeam />
110-
</Flex>
111-
</Box>
71+
<CustomCard title="Transfer Ownership">
72+
<TransferTeam />
73+
</CustomCard>
11274

113-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
114-
<Text fontWeight="bold" mb={4}>
115-
Danger Zone
116-
</Text>
117-
<Flex>
118-
<DeleteTeam />
119-
</Flex>
120-
</Box>
75+
<CustomCard title="Danger Zone">
76+
<DeleteTeam />
77+
</CustomCard>
12178
</>
12279
)}
12380
</Container>

frontend/src/components/UserSettings/UserInformation.tsx

Lines changed: 30 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
import {
2-
Box,
3-
Button,
4-
Container,
5-
Flex,
6-
Heading,
7-
Text,
8-
useDisclosure,
9-
} from "@chakra-ui/react"
1+
import { Button, Container, useDisclosure } from "@chakra-ui/react"
102
import { useMutation, useQueryClient } from "@tanstack/react-query"
113
import { useState } from "react"
124
import { FaGithub } from "react-icons/fa"
@@ -15,6 +7,7 @@ import { UsersService } from "../../client"
157
import { useCurrentUser } from "../../hooks/useAuth"
168
import useCustomToast from "../../hooks/useCustomToast"
179
import { handleError } from "../../utils"
10+
import CustomCard from "../Common/CustomCard"
1811
import EditableField from "../Common/EditableField"
1912
import UpdateEmailVerification from "../Common/UpdateEmailVerification"
2013
import ChangePassword from "./ChangePassword"
@@ -58,67 +51,34 @@ const UserInformation = () => {
5851

5952
return (
6053
<>
61-
<Container maxW="full" m={4}>
62-
<Heading size="sm">User Information</Heading>
63-
<Text py={2} mb={4}>
64-
See and manage your user information.
65-
</Text>
66-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
67-
<Box my={4}>
68-
<Text fontWeight="bold" mb={4}>
69-
Full Name
70-
</Text>
71-
<EditableField
72-
type="full_name"
73-
value={currentUser?.full_name ?? ""}
74-
onSubmit={(newFullName) => fullNameMutation.mutate(newFullName)}
75-
canEdit={true}
76-
/>
77-
</Box>
78-
</Box>
79-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
80-
<Box my={4}>
81-
<Text fontWeight="bold" mb={4}>
82-
Email
83-
</Text>
84-
<EditableField
85-
type="email"
86-
value={currentUser?.email ?? ""}
87-
onSubmit={(newEmail) => emailMutation.mutate(newEmail)}
88-
canEdit={true}
89-
/>
90-
</Box>
91-
</Box>
92-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
93-
<Box my={4}>
94-
<Text fontWeight="bold" mb={4}>
95-
Password
96-
</Text>
97-
<ChangePassword />
98-
</Box>
99-
</Box>
100-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
101-
<Box my={4}>
102-
<Text fontWeight="bold" mb={4}>
103-
Connect with Github
104-
</Text>
105-
<Button
106-
variant="outline"
107-
colorScheme="gray"
108-
leftIcon={<FaGithub />}
109-
>
110-
Connect
111-
</Button>
112-
</Box>
113-
</Box>
114-
<Box boxShadow="xs" px={8} py={4} borderRadius="lg" mb={8}>
115-
<Text fontWeight="bold" mb={4}>
116-
Danger Zone
117-
</Text>
118-
<Flex>
119-
<DeleteAccount />
120-
</Flex>
121-
</Box>
54+
<Container maxW="full" my={4} p={0}>
55+
<CustomCard title="Full Name">
56+
<EditableField
57+
type="full_name"
58+
value={currentUser?.full_name ?? ""}
59+
onSubmit={(newFullName) => fullNameMutation.mutate(newFullName)}
60+
canEdit={true}
61+
/>
62+
</CustomCard>
63+
<CustomCard title="Email">
64+
<EditableField
65+
type="email"
66+
value={currentUser?.email ?? ""}
67+
onSubmit={(newEmail) => emailMutation.mutate(newEmail)}
68+
canEdit={true}
69+
/>
70+
</CustomCard>
71+
<CustomCard title="Password">
72+
<ChangePassword />
73+
</CustomCard>
74+
<CustomCard title="Connect with Github">
75+
<Button variant="outline" colorScheme="gray" leftIcon={<FaGithub />}>
76+
Connect
77+
</Button>
78+
</CustomCard>
79+
<CustomCard title="Danger Zone">
80+
<DeleteAccount />
81+
</CustomCard>
12282
</Container>
12383
{showUpdateEmailModal && (
12484
<UpdateEmailVerification isOpen={isOpen} onClose={onClose} />

0 commit comments

Comments
 (0)