🛂 Migrate to Chakra UI v3 (#1496)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Alejandra
2025-02-17 20:33:00 +01:00
committed by GitHub
co-authored by github-actions
parent 74e2604faf
commit 55df823739
60 changed files with 4682 additions and 4399 deletions
@@ -1,15 +1,9 @@
import {
Badge,
Container,
Heading,
Radio,
RadioGroup,
Stack,
useColorMode,
} from "@chakra-ui/react"
import { Container, Heading, Stack } from "@chakra-ui/react"
import { useTheme } from "next-themes"
import { Radio, RadioGroup } from "../../components/ui/radio"
const Appearance = () => {
const { colorMode, toggleColorMode } = useColorMode()
const { theme, setTheme } = useTheme()
return (
<>
@@ -17,18 +11,16 @@ const Appearance = () => {
<Heading size="sm" py={4}>
Appearance
</Heading>
<RadioGroup onChange={toggleColorMode} value={colorMode}>
<RadioGroup
onValueChange={(e) => setTheme(e.value)}
value={theme}
colorPalette="teal"
>
<Stack>
{/* TODO: Add system default option */}
<Radio value="light" colorScheme="teal">
Light Mode
<Badge ml="1" colorScheme="teal">
Default
</Badge>
</Radio>
<Radio value="dark" colorScheme="teal">
Dark Mode
</Radio>
<Radio value="system">System</Radio>
<Radio value="light">Light Mode</Radio>
<Radio value="dark">Dark Mode</Radio>
</Stack>
</RadioGroup>
</Container>
@@ -1,34 +1,25 @@
import {
Box,
Button,
Container,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Input,
useColorModeValue,
} from "@chakra-ui/react"
import { Box, Button, Container, Heading, VStack } from "@chakra-ui/react"
import { useMutation } from "@tanstack/react-query"
import { type SubmitHandler, useForm } from "react-hook-form"
import { FiLock } from "react-icons/fi"
import { type ApiError, type UpdatePassword, UsersService } from "../../client"
import useCustomToast from "../../hooks/useCustomToast"
import { confirmPasswordRules, handleError, passwordRules } from "../../utils"
import { PasswordInput } from "../ui/password-input"
interface UpdatePasswordForm extends UpdatePassword {
confirm_password: string
}
const ChangePassword = () => {
const color = useColorModeValue("inherit", "ui.light")
const showToast = useCustomToast()
const { showSuccessToast } = useCustomToast()
const {
register,
handleSubmit,
reset,
getValues,
formState: { errors, isSubmitting },
formState: { errors, isValid, isSubmitting },
} = useForm<UpdatePasswordForm>({
mode: "onBlur",
criteriaMode: "all",
@@ -38,11 +29,11 @@ const ChangePassword = () => {
mutationFn: (data: UpdatePassword) =>
UsersService.updatePasswordMe({ requestBody: data }),
onSuccess: () => {
showToast("Success!", "Password updated successfully.", "success")
showSuccessToast("Password updated successfully.")
reset()
},
onError: (err: ApiError) => {
handleError(err, showToast)
handleError(err)
},
})
@@ -57,60 +48,39 @@ const ChangePassword = () => {
Change Password
</Heading>
<Box
w={{ sm: "full", md: "50%" }}
w={{ sm: "full", md: "300px" }}
as="form"
onSubmit={handleSubmit(onSubmit)}
>
<FormControl isRequired isInvalid={!!errors.current_password}>
<FormLabel color={color} htmlFor="current_password">
Current Password
</FormLabel>
<Input
id="current_password"
{...register("current_password")}
placeholder="Password"
type="password"
w="auto"
<VStack gap={4}>
<PasswordInput
type="current_password"
startElement={<FiLock />}
{...register("current_password", passwordRules())}
placeholder="Current Password"
errors={errors}
/>
{errors.current_password && (
<FormErrorMessage>
{errors.current_password.message}
</FormErrorMessage>
)}
</FormControl>
<FormControl mt={4} isRequired isInvalid={!!errors.new_password}>
<FormLabel htmlFor="password">Set Password</FormLabel>
<Input
id="password"
<PasswordInput
type="new_password"
startElement={<FiLock />}
{...register("new_password", passwordRules())}
placeholder="Password"
type="password"
w="auto"
placeholder="New Password"
errors={errors}
/>
{errors.new_password && (
<FormErrorMessage>{errors.new_password.message}</FormErrorMessage>
)}
</FormControl>
<FormControl mt={4} isRequired isInvalid={!!errors.confirm_password}>
<FormLabel htmlFor="confirm_password">Confirm Password</FormLabel>
<Input
id="confirm_password"
<PasswordInput
type="confirm_password"
startElement={<FiLock />}
{...register("confirm_password", confirmPasswordRules(getValues))}
placeholder="Password"
type="password"
w="auto"
placeholder="Confirm Password"
errors={errors}
/>
{errors.confirm_password && (
<FormErrorMessage>
{errors.confirm_password.message}
</FormErrorMessage>
)}
</FormControl>
</VStack>
<Button
variant="primary"
variant="solid"
mt={4}
type="submit"
isLoading={isSubmitting}
loading={isSubmitting}
disabled={!isValid}
>
Save
</Button>
@@ -1,35 +1,19 @@
import {
Button,
Container,
Heading,
Text,
useDisclosure,
} from "@chakra-ui/react"
import { Container, Heading, Text } from "@chakra-ui/react"
import DeleteConfirmation from "./DeleteConfirmation"
const DeleteAccount = () => {
const confirmationModal = useDisclosure()
return (
<>
<Container maxW="full">
<Heading size="sm" py={4}>
Delete Account
</Heading>
<Text>
Permanently delete your data and everything associated with your
account.
</Text>
<Button variant="danger" mt={4} onClick={confirmationModal.onOpen}>
Delete
</Button>
<DeleteConfirmation
isOpen={confirmationModal.isOpen}
onClose={confirmationModal.onClose}
/>
</Container>
</>
<Container maxW="full">
<Heading size="sm" py={4}>
Delete Account
</Heading>
<Text>
Permanently delete your data and everything associated with your
account.
</Text>
<DeleteConfirmation />
</Container>
)
}
export default DeleteAccount
@@ -1,30 +1,27 @@
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button,
} from "@chakra-ui/react"
import { Button, ButtonGroup, Text } from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import React from "react"
import { useState } from "react"
import { useForm } from "react-hook-form"
import { type ApiError, UsersService } from "../../client"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog"
import useAuth from "../../hooks/useAuth"
import useCustomToast from "../../hooks/useCustomToast"
import { handleError } from "../../utils"
interface DeleteProps {
isOpen: boolean
onClose: () => void
}
const DeleteConfirmation = ({ isOpen, onClose }: DeleteProps) => {
const DeleteConfirmation = () => {
const [isOpen, setIsOpen] = useState(false)
const queryClient = useQueryClient()
const showToast = useCustomToast()
const cancelRef = React.useRef<HTMLButtonElement | null>(null)
const { showSuccessToast } = useCustomToast()
const {
handleSubmit,
formState: { isSubmitting },
@@ -34,16 +31,12 @@ const DeleteConfirmation = ({ isOpen, onClose }: DeleteProps) => {
const mutation = useMutation({
mutationFn: () => UsersService.deleteUserMe(),
onSuccess: () => {
showToast(
"Success",
"Your account has been successfully deleted.",
"success",
)
showSuccessToast("Your account has been successfully deleted")
setIsOpen(false)
logout()
onClose()
},
onError: (err: ApiError) => {
handleError(err, showToast)
handleError(err)
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["currentUser"] })
@@ -56,39 +49,58 @@ const DeleteConfirmation = ({ isOpen, onClose }: DeleteProps) => {
return (
<>
<AlertDialog
isOpen={isOpen}
onClose={onClose}
leastDestructiveRef={cancelRef}
size={{ base: "sm", md: "md" }}
isCentered
<DialogRoot
size={{ base: "xs", md: "md" }}
role="alertdialog"
placement="center"
open={isOpen}
onOpenChange={({ open }) => setIsOpen(open)}
>
<AlertDialogOverlay>
<AlertDialogContent as="form" onSubmit={handleSubmit(onSubmit)}>
<AlertDialogHeader>Confirmation Required</AlertDialogHeader>
<DialogTrigger asChild>
<Button variant="solid" colorPalette="red" mt={4}>
Delete
</Button>
</DialogTrigger>
<AlertDialogBody>
All your account data will be{" "}
<strong>permanently deleted.</strong> If you are sure, please
click <strong>"Confirm"</strong> to proceed. This action cannot be
undone.
</AlertDialogBody>
<DialogContent>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogCloseTrigger />
<DialogHeader>
<DialogTitle>Confirmation Required</DialogTitle>
</DialogHeader>
<DialogBody>
<Text mb={4}>
All your account data will be{" "}
<strong>permanently deleted.</strong> If you are sure, please
click <strong>"Confirm"</strong> to proceed. This action cannot
be undone.
</Text>
</DialogBody>
<AlertDialogFooter gap={3}>
<Button variant="danger" type="submit" isLoading={isSubmitting}>
Confirm
</Button>
<Button
ref={cancelRef}
onClick={onClose}
isDisabled={isSubmitting}
>
Cancel
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
<DialogFooter gap={2}>
<ButtonGroup>
<DialogActionTrigger asChild>
<Button
variant="subtle"
colorPalette="gray"
disabled={isSubmitting}
>
Cancel
</Button>
</DialogActionTrigger>
<Button
variant="solid"
colorPalette="red"
type="submit"
loading={isSubmitting}
>
Delete
</Button>
</ButtonGroup>
</DialogFooter>
</form>
</DialogContent>
</DialogRoot>
</>
)
}
@@ -3,13 +3,9 @@ import {
Button,
Container,
Flex,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Input,
Text,
useColorModeValue,
} from "@chakra-ui/react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { useState } from "react"
@@ -24,11 +20,11 @@ import {
import useAuth from "../../hooks/useAuth"
import useCustomToast from "../../hooks/useCustomToast"
import { emailPattern, handleError } from "../../utils"
import { Field } from "../ui/field"
const UserInformation = () => {
const queryClient = useQueryClient()
const color = useColorModeValue("inherit", "ui.light")
const showToast = useCustomToast()
const { showSuccessToast } = useCustomToast()
const [editMode, setEditMode] = useState(false)
const { user: currentUser } = useAuth()
const {
@@ -54,10 +50,10 @@ const UserInformation = () => {
mutationFn: (data: UserUpdateMe) =>
UsersService.updateUserMe({ requestBody: data }),
onSuccess: () => {
showToast("Success!", "User updated successfully.", "success")
showSuccessToast("User updated successfully.")
},
onError: (err: ApiError) => {
handleError(err, showToast)
handleError(err)
},
onSettled: () => {
queryClient.invalidateQueries()
@@ -84,13 +80,9 @@ const UserInformation = () => {
as="form"
onSubmit={handleSubmit(onSubmit)}
>
<FormControl>
<FormLabel color={color} htmlFor="name">
Full name
</FormLabel>
<Field label="Full name">
{editMode ? (
<Input
id="name"
{...register("full_name", { maxLength: 30 })}
type="text"
size="md"
@@ -98,23 +90,24 @@ const UserInformation = () => {
/>
) : (
<Text
size="md"
fontSize="md"
py={2}
color={!currentUser?.full_name ? "ui.dim" : "inherit"}
isTruncated
color={!currentUser?.full_name ? "gray" : "inherit"}
truncate
maxWidth="250px"
>
{currentUser?.full_name || "N/A"}
</Text>
)}
</FormControl>
<FormControl mt={4} isInvalid={!!errors.email}>
<FormLabel color={color} htmlFor="email">
Email
</FormLabel>
</Field>
<Field
mt={4}
label="Email"
invalid={!!errors.email}
errorText={errors.email?.message}
>
{editMode ? (
<Input
id="email"
{...register("email", {
required: "Email is required",
pattern: emailPattern,
@@ -124,26 +117,28 @@ const UserInformation = () => {
w="auto"
/>
) : (
<Text size="md" py={2} isTruncated maxWidth="250px">
<Text fontSize="md" py={2} truncate maxWidth="250px">
{currentUser?.email}
</Text>
)}
{errors.email && (
<FormErrorMessage>{errors.email.message}</FormErrorMessage>
)}
</FormControl>
</Field>
<Flex mt={4} gap={3}>
<Button
variant="primary"
variant="solid"
onClick={toggleEditMode}
type={editMode ? "button" : "submit"}
isLoading={editMode ? isSubmitting : false}
isDisabled={editMode ? !isDirty || !getValues("email") : false}
loading={editMode ? isSubmitting : false}
disabled={editMode ? !isDirty || !getValues("email") : false}
>
{editMode ? "Save" : "Edit"}
</Button>
{editMode && (
<Button onClick={onCancel} isDisabled={isSubmitting}>
<Button
variant="subtle"
colorPalette="gray"
onClick={onCancel}
disabled={isSubmitting}
>
Cancel
</Button>
)}