committed by
GitHub
20 changed files with 927 additions and 81 deletions
@ -0,0 +1,39 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, Menu, MenuButton, MenuItem, MenuList, useDisclosure } from '@chakra-ui/react'; |
|||
import { BsThreeDotsVertical } from 'react-icons/bs'; |
|||
import { FiTrash, FiEdit } from 'react-icons/fi'; |
|||
|
|||
import Delete from '../pages/modals/DeleteAlert'; |
|||
import EditUser from '../pages/modals/EditUser'; |
|||
import EditItem from '../pages/modals/EditItem'; |
|||
|
|||
interface ActionsMenuProps { |
|||
type: string; |
|||
id: number; |
|||
} |
|||
|
|||
const ActionsMenu: React.FC<ActionsMenuProps> = ({ type, id }) => { |
|||
const editUserModal = useDisclosure(); |
|||
const deleteModal = useDisclosure(); |
|||
|
|||
return ( |
|||
<> |
|||
<Menu> |
|||
<MenuButton as={Button} bg="white" rightIcon={<BsThreeDotsVertical />} variant="unstyled"> |
|||
</MenuButton> |
|||
<MenuList> |
|||
<MenuItem onClick={editUserModal.onOpen} icon={<FiEdit fontSize="16px" />}>Edit {type}</MenuItem> |
|||
<MenuItem onClick={deleteModal.onOpen} icon={<FiTrash fontSize="16px" />} color="ui.danger">Delete {type}</MenuItem> |
|||
</MenuList> |
|||
{ |
|||
type === "User" ? <EditUser isOpen={editUserModal.isOpen} onClose={editUserModal.onClose} /> |
|||
: <EditItem isOpen={editUserModal.isOpen} onClose={editUserModal.onClose} /> |
|||
} |
|||
<Delete type={type} id={id} isOpen={deleteModal.isOpen} onClose={deleteModal.onClose} /> |
|||
</Menu> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default ActionsMenu; |
@ -0,0 +1,30 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, Flex, Icon, useDisclosure } from '@chakra-ui/react'; |
|||
import { FaPlus } from "react-icons/fa"; |
|||
|
|||
import CreateItem from '../pages/modals/CreateItem'; |
|||
import CreateUser from '../pages/modals/CreateUser'; |
|||
|
|||
interface NavbarProps { |
|||
type: string; |
|||
} |
|||
|
|||
const Navbar: React.FC<NavbarProps> = ({ type }) => { |
|||
const createUserModal = useDisclosure(); |
|||
const createItemModal = useDisclosure(); |
|||
|
|||
return ( |
|||
<> |
|||
<Flex gap={4} py={{ base: "8", md: "4" }} justify={{ base: "center", md: "end" }}> |
|||
<Button bg="ui.main" color="white" gap={1} fontSize={{ base: "sm", md: "inherit" }} onClick={type === "User" ? createUserModal.onOpen : createItemModal.onOpen}> |
|||
<Icon as={FaPlus} /> Create {type} |
|||
</Button> |
|||
<CreateUser isOpen={createUserModal.isOpen} onClose={createUserModal.onClose} /> |
|||
<CreateItem isOpen={createItemModal.isOpen} onClose={createItemModal.onClose} /> |
|||
</Flex> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default Navbar; |
@ -0,0 +1,89 @@ |
|||
import React, { useEffect, useState } from 'react'; |
|||
|
|||
import { Box, Container, Flex, Heading, Spinner, Table, TableContainer, Tbody, Td, Th, Thead, Tr, useToast } from '@chakra-ui/react'; |
|||
|
|||
import ActionsMenu from '../../components/ActionsMenu'; |
|||
import Navbar from '../../components/Navbar'; |
|||
import { useUsersStore } from '../../store/users-store'; |
|||
|
|||
const Admin: React.FC = () => { |
|||
const toast = useToast(); |
|||
const [isLoading, setIsLoading] = useState(false); |
|||
const { users, getUsers } = useUsersStore(); |
|||
|
|||
useEffect(() => { |
|||
const fetchUsers = async () => { |
|||
try { |
|||
setIsLoading(true); |
|||
await getUsers(); |
|||
setIsLoading(false); |
|||
} catch (err) { |
|||
setIsLoading(false); |
|||
toast({ |
|||
title: 'Something went wrong.', |
|||
description: 'Failed to fetch users. Please try again.', |
|||
status: 'error', |
|||
isClosable: true, |
|||
}); |
|||
} |
|||
} |
|||
fetchUsers(); |
|||
}, []) |
|||
|
|||
return ( |
|||
<> |
|||
{isLoading ? ( |
|||
// TODO: Add skeleton
|
|||
<Flex justify="center" align="center" height="100vh" width="full"> |
|||
<Spinner size="xl" color='ui.main'/> |
|||
</Flex> |
|||
) : ( |
|||
users && |
|||
<Container maxW="full"> |
|||
<Heading size="lg" color="gray.700" textAlign={{ base: "center", md: "left" }} pt={12}> |
|||
User Management |
|||
</Heading> |
|||
<Navbar type={"User"} /> |
|||
<TableContainer> |
|||
<Table fontSize="md" size={{ base: "sm", md: "md" }}> |
|||
<Thead> |
|||
<Tr> |
|||
<Th>Full name</Th> |
|||
<Th>Email</Th> |
|||
<Th>Role</Th> |
|||
<Th>Status</Th> |
|||
</Tr> |
|||
</Thead> |
|||
<Tbody> |
|||
{users.map((user) => ( |
|||
<Tr key={user.id}> |
|||
<Td color={!user.full_name ? "gray.600" : "inherit"}>{user.full_name || "N/A"}</Td> |
|||
<Td>{user.email}</Td> |
|||
<Td>{user.is_superuser ? "Superuser" : "User"}</Td> |
|||
<Td> |
|||
<Flex gap={2}> |
|||
<Box |
|||
w="2" |
|||
h="2" |
|||
borderRadius="50%" |
|||
bg={user.is_active ? "ui.success" : "ui.danger"} |
|||
alignSelf="center" |
|||
/> |
|||
{user.is_active ? "Active" : "Inactive"} |
|||
</Flex> |
|||
</Td> |
|||
<Td> |
|||
<ActionsMenu type="User" id={user.id} /> |
|||
</Td> |
|||
</Tr> |
|||
))} |
|||
</Tbody> |
|||
</Table> |
|||
</TableContainer> |
|||
</Container> |
|||
)} |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default Admin; |
@ -0,0 +1,24 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Box, Text } from '@chakra-ui/react'; |
|||
|
|||
import { useUserStore } from '../../store/user-store'; |
|||
|
|||
|
|||
const Dashboard: React.FC = () => { |
|||
const { user } = useUserStore(); |
|||
|
|||
return ( |
|||
<> |
|||
{user ? ( |
|||
<Box width="100%" p={8}> |
|||
<Text fontSize="24px">Hi, {user.full_name || user.email} 👋🏼</Text> |
|||
<Text>Welcome back, nice to see you again!</Text> |
|||
</Box> |
|||
) : null} |
|||
</> |
|||
|
|||
) |
|||
} |
|||
|
|||
export default Dashboard; |
@ -0,0 +1,78 @@ |
|||
import React, { useEffect, useState } from 'react'; |
|||
|
|||
import { Container, Flex, Heading, Spinner, Table, TableContainer, Tbody, Td, Th, Thead, Tr, useToast } from '@chakra-ui/react'; |
|||
|
|||
import ActionsMenu from '../../components/ActionsMenu'; |
|||
import Navbar from '../../components/Navbar'; |
|||
import { useItemsStore } from '../../store/items-store'; |
|||
|
|||
|
|||
const Items: React.FC = () => { |
|||
const toast = useToast(); |
|||
const [isLoading, setIsLoading] = useState(false); |
|||
const { items, getItems } = useItemsStore(); |
|||
|
|||
useEffect(() => { |
|||
const fetchItems = async () => { |
|||
try { |
|||
setIsLoading(true); |
|||
await getItems(); |
|||
setIsLoading(false); |
|||
} catch (err) { |
|||
setIsLoading(false); |
|||
toast({ |
|||
title: 'Something went wrong.', |
|||
description: 'Failed to fetch items. Please try again.', |
|||
status: 'error', |
|||
isClosable: true, |
|||
}); |
|||
} |
|||
} |
|||
fetchItems(); |
|||
}, []) |
|||
|
|||
|
|||
return ( |
|||
<> |
|||
{isLoading ? ( |
|||
// TODO: Add skeleton
|
|||
<Flex justify="center" align="center" height="100vh" width="full"> |
|||
<Spinner size="xl" color='ui.main' /> |
|||
</Flex> |
|||
) : ( |
|||
items && |
|||
<Container maxW="full"> |
|||
<Heading size="lg" color="gray.700" textAlign={{ base: "center", md: "left" }} pt={12}> |
|||
Items Management |
|||
</Heading> |
|||
<Navbar type={"Item"} /> |
|||
<TableContainer> |
|||
<Table size={{ base: "sm", md: "md" }}> |
|||
<Thead> |
|||
<Tr> |
|||
<Th>ID</Th> |
|||
<Th>Title</Th> |
|||
<Th>Description</Th> |
|||
</Tr> |
|||
</Thead> |
|||
<Tbody> |
|||
{items.map((item) => ( |
|||
<Tr key={item.id}> |
|||
<Td>{item.id}</Td> |
|||
<Td>{item.title}</Td> |
|||
<Td color={!item.description ? "gray.600" : "inherit"}>{item.description || "N/A"}</Td> |
|||
<Td> |
|||
<ActionsMenu type={"Item"} id={item.id} /> |
|||
</Td> |
|||
</Tr> |
|||
))} |
|||
</Tbody> |
|||
</Table> |
|||
</TableContainer> |
|||
</Container> |
|||
)} |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default Items; |
@ -0,0 +1,49 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Container, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react'; |
|||
|
|||
import Appearance from '../panels/Appearance'; |
|||
import ChangePassword from '../panels/ChangePassword'; |
|||
import DeleteAccount from '../panels/DeleteAccount'; |
|||
import UserInformation from '../panels/UserInformation'; |
|||
|
|||
|
|||
|
|||
const Profile: React.FC = () => { |
|||
|
|||
return ( |
|||
<> |
|||
<Container maxW="full"> |
|||
<Heading size="lg" color="gray.700" textAlign={{ base: "center", md: "left" }} py={12}> |
|||
User Settings |
|||
</Heading> |
|||
<Tabs variant='enclosed' > |
|||
<TabList> |
|||
<Tab>Profile</Tab> |
|||
<Tab>Password</Tab> |
|||
<Tab>Appearance</Tab> |
|||
<Tab>Danger zone</Tab> |
|||
</TabList> |
|||
<TabPanels> |
|||
<TabPanel> |
|||
<UserInformation /> |
|||
</TabPanel> |
|||
<TabPanel> |
|||
<ChangePassword /> |
|||
</TabPanel> |
|||
<TabPanel> |
|||
<Appearance /> |
|||
</TabPanel> |
|||
<TabPanel> |
|||
<DeleteAccount /> |
|||
</TabPanel> |
|||
|
|||
</TabPanels> |
|||
</Tabs> |
|||
</Container> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default Profile; |
|||
|
@ -0,0 +1,89 @@ |
|||
import React, { useState } from 'react'; |
|||
|
|||
import { Button, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, useToast } from '@chakra-ui/react'; |
|||
import { SubmitHandler, useForm } from 'react-hook-form'; |
|||
|
|||
import { ItemCreate } from '../../client'; |
|||
import { useItemsStore } from '../../store/items-store'; |
|||
|
|||
interface CreateItemProps { |
|||
isOpen: boolean; |
|||
onClose: () => void; |
|||
} |
|||
|
|||
const CreateItem: React.FC<CreateItemProps> = ({ isOpen, onClose }) => { |
|||
const toast = useToast(); |
|||
const [isLoading, setIsLoading] = useState(false); |
|||
const { register, handleSubmit } = useForm<ItemCreate>(); |
|||
const { addItem } = useItemsStore(); |
|||
|
|||
const onSubmit: SubmitHandler<ItemCreate> = async (data) => { |
|||
try { |
|||
setIsLoading(true); |
|||
await addItem(data); |
|||
setIsLoading(false); |
|||
|
|||
toast({ |
|||
title: 'Success!', |
|||
description: 'Item created successfully.', |
|||
status: 'success', |
|||
isClosable: true, |
|||
}); |
|||
onClose(); |
|||
} catch (err) { |
|||
setIsLoading(false); |
|||
toast({ |
|||
title: 'Something went wrong.', |
|||
description: 'Failed to create item. Please try again.', |
|||
status: 'error', |
|||
isClosable: true, |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<Modal |
|||
isOpen={isOpen} |
|||
onClose={onClose} |
|||
size={{ base: 'sm', md: 'md' }} |
|||
isCentered |
|||
> |
|||
<ModalOverlay /> |
|||
<ModalContent as="form" onSubmit={handleSubmit(onSubmit)}> |
|||
<ModalHeader>Create Item</ModalHeader> |
|||
<ModalCloseButton /> |
|||
<ModalBody pb={6}> |
|||
<FormControl> |
|||
<FormLabel>Title</FormLabel> |
|||
<Input |
|||
{...register('title')} |
|||
placeholder="Title" |
|||
|
|||
/> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel>Description</FormLabel> |
|||
<Input |
|||
{...register('description')} |
|||
placeholder="Description" |
|||
|
|||
/> |
|||
</FormControl> |
|||
</ModalBody> |
|||
|
|||
<ModalFooter gap={3}> |
|||
<Button bg="ui.main" color="white" type="submit" isLoading={isLoading}> |
|||
Save |
|||
</Button> |
|||
<Button onClick={onClose} isDisabled={isLoading}> |
|||
Cancel |
|||
</Button> |
|||
</ModalFooter> |
|||
</ModalContent> |
|||
</Modal> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default CreateItem; |
@ -0,0 +1,96 @@ |
|||
import React, { useState } from 'react'; |
|||
|
|||
import { Box, Button, Checkbox, Flex, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Spinner, useToast } from '@chakra-ui/react'; |
|||
import { SubmitHandler, useForm } from 'react-hook-form'; |
|||
|
|||
import { UserCreate } from '../../client'; |
|||
import { useUsersStore } from '../../store/users-store'; |
|||
|
|||
interface CreateUserProps { |
|||
isOpen: boolean; |
|||
onClose: () => void; |
|||
} |
|||
|
|||
const CreateUser: React.FC<CreateUserProps> = ({ isOpen, onClose }) => { |
|||
const toast = useToast(); |
|||
const [isLoading, setIsLoading] = useState(false); |
|||
const { register, handleSubmit } = useForm<UserCreate>(); |
|||
const { addUser } = useUsersStore(); |
|||
|
|||
const onSubmit: SubmitHandler<UserCreate> = async (data) => { |
|||
try { |
|||
setIsLoading(true); |
|||
await addUser(data); |
|||
setIsLoading(false); |
|||
toast({ |
|||
title: 'Success!', |
|||
description: 'User created successfully.', |
|||
status: 'success', |
|||
isClosable: true, |
|||
}); |
|||
onClose(); |
|||
|
|||
} catch (err) { |
|||
setIsLoading(false); |
|||
toast({ |
|||
title: 'Something went wrong.', |
|||
description: 'Failed to create user. Please try again.', |
|||
status: 'error', |
|||
isClosable: true, |
|||
}); |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<Modal |
|||
isOpen={isOpen} |
|||
onClose={onClose} |
|||
size={{ base: "sm", md: "md" }} |
|||
isCentered |
|||
> |
|||
<ModalOverlay /> |
|||
<ModalContent as="form" onSubmit={handleSubmit(onSubmit)}> |
|||
{/* TODO: Check passwords */} |
|||
<ModalHeader>Create User</ModalHeader> |
|||
<ModalCloseButton /> |
|||
<ModalBody pb={6}> |
|||
<FormControl> |
|||
<FormLabel>Email</FormLabel> |
|||
<Input {...register('email')} placeholder='Email' type="email" /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel>Full name</FormLabel> |
|||
<Input {...register('full_name')} placeholder='Full name' type="text" /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel>Set Password</FormLabel> |
|||
<Input {...register('password')} placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel>Confirm Password</FormLabel> |
|||
<Input placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<Flex> |
|||
<FormControl mt={4}> |
|||
<Checkbox {...register('is_superuser')} colorScheme='teal'>Is superuser?</Checkbox> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<Checkbox {...register('is_active')} colorScheme='teal'>Is active?</Checkbox> |
|||
</FormControl> |
|||
</Flex> |
|||
</ModalBody> |
|||
|
|||
<ModalFooter gap={3}> |
|||
<Button bg="ui.main" color="white" type="submit" isLoading={isLoading}> |
|||
Save |
|||
</Button> |
|||
<Button onClick={onClose}>Cancel</Button> |
|||
</ModalFooter> |
|||
</ModalContent> |
|||
</Modal> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default CreateUser; |
@ -0,0 +1,68 @@ |
|||
import React, { useState } from 'react'; |
|||
|
|||
import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button } from '@chakra-ui/react'; |
|||
import { useForm } from 'react-hook-form'; |
|||
|
|||
import { useItemsStore } from '../../store/items-store'; |
|||
|
|||
interface DeleteProps { |
|||
toDelete: string; |
|||
id: number |
|||
isOpen: boolean; |
|||
onClose: () => void; |
|||
} |
|||
|
|||
const Delete: React.FC<DeleteProps> = ({ toDelete, id, isOpen, onClose }) => { |
|||
const cancelRef = React.useRef<HTMLButtonElement | null>(null); |
|||
const [isLoading, setIsLoading] = useState(false); |
|||
const { handleSubmit } = useForm(); |
|||
const { deleteItem } = useItemsStore(); |
|||
|
|||
const onSubmit = async () => { |
|||
try { |
|||
setIsLoading(true); |
|||
await deleteItem(id); |
|||
setIsLoading(false); |
|||
onClose(); |
|||
} catch (err) { |
|||
setIsLoading(false); |
|||
console.error(err); |
|||
|
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<AlertDialog |
|||
isOpen={isOpen} |
|||
onClose={onClose} |
|||
leastDestructiveRef={cancelRef} |
|||
size={{ base: "sm", md: "md" }} |
|||
isCentered |
|||
> |
|||
<AlertDialogOverlay> |
|||
<AlertDialogContent as="form" onSubmit={handleSubmit(onSubmit)}> |
|||
<AlertDialogHeader fontSize='lg' fontWeight='bold'> |
|||
Delete {toDelete} |
|||
</AlertDialogHeader> |
|||
|
|||
<AlertDialogBody> |
|||
Are you sure? You will not be able to undo this action. |
|||
</AlertDialogBody> |
|||
|
|||
<AlertDialogFooter gap={3}> |
|||
<Button colorScheme='red' type="submit" isLoading={isLoading}> |
|||
Delete |
|||
</Button> |
|||
<Button ref={cancelRef} onClick={onClose} isDisabled={isLoading}> |
|||
Cancel |
|||
</Button> |
|||
</AlertDialogFooter> |
|||
</AlertDialogContent> |
|||
</AlertDialogOverlay> |
|||
</AlertDialog> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default Delete; |
@ -0,0 +1,48 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay } from '@chakra-ui/react'; |
|||
|
|||
interface EditItemProps { |
|||
isOpen: boolean; |
|||
onClose: () => void; |
|||
} |
|||
|
|||
const EditItem: React.FC<EditItemProps> = ({ isOpen, onClose }) => { |
|||
|
|||
return ( |
|||
<> |
|||
<Modal |
|||
isOpen={isOpen} |
|||
onClose={onClose} |
|||
size={{ base: "sm", md: "md" }} |
|||
isCentered |
|||
> |
|||
<ModalOverlay /> |
|||
<ModalContent> |
|||
<ModalHeader>Edit Item</ModalHeader> |
|||
<ModalCloseButton /> |
|||
<ModalBody pb={6}> |
|||
<FormControl> |
|||
<FormLabel>Item</FormLabel> |
|||
<Input placeholder='Item' /> |
|||
</FormControl> |
|||
|
|||
<FormControl mt={4}> |
|||
<FormLabel>Description</FormLabel> |
|||
<Input placeholder='Description' /> |
|||
</FormControl> |
|||
</ModalBody> |
|||
|
|||
<ModalFooter gap={3}> |
|||
<Button colorScheme='teal'> |
|||
Save |
|||
</Button> |
|||
<Button onClick={onClose}>Cancel</Button> |
|||
</ModalFooter> |
|||
</ModalContent> |
|||
</Modal> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default EditItem; |
@ -0,0 +1,60 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, Checkbox, Flex, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, useDisclosure } from '@chakra-ui/react'; |
|||
|
|||
interface EditUserProps { |
|||
isOpen: boolean; |
|||
onClose: () => void; |
|||
} |
|||
|
|||
const EditUser: React.FC<EditUserProps> = ({ isOpen, onClose }) => { |
|||
|
|||
return ( |
|||
<> |
|||
<Modal |
|||
isOpen={isOpen} |
|||
onClose={onClose} |
|||
size={{ base: "sm", md: "md" }} |
|||
isCentered |
|||
> |
|||
<ModalOverlay /> |
|||
<ModalContent> |
|||
<ModalHeader>Edit User</ModalHeader> |
|||
<ModalCloseButton /> |
|||
<ModalBody pb={6}> |
|||
<FormControl> |
|||
<FormLabel>Email</FormLabel> |
|||
<Input placeholder='Email' /> |
|||
</FormControl> |
|||
|
|||
<FormControl mt={4}> |
|||
<FormLabel>Full name</FormLabel> |
|||
<Input placeholder='Full name' /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel>Set Password</FormLabel> |
|||
<Input placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<Flex> |
|||
<FormControl mt={4}> |
|||
<Checkbox colorScheme='teal'>Is superuser?</Checkbox> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<Checkbox colorScheme='teal'>Is active?</Checkbox> |
|||
</FormControl> |
|||
</Flex> |
|||
</ModalBody> |
|||
|
|||
<ModalFooter gap={3}> |
|||
<Button colorScheme='teal'> |
|||
Save |
|||
</Button> |
|||
<Button onClick={onClose}>Cancel</Button> |
|||
</ModalFooter> |
|||
</ModalContent> |
|||
</Modal> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default EditUser; |
@ -0,0 +1,32 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, Container, Heading, Radio, RadioGroup, Stack } from '@chakra-ui/react'; |
|||
|
|||
const Appearance: React.FC = () => { |
|||
const [value, setValue] = React.useState('system'); |
|||
|
|||
return ( |
|||
<> |
|||
<Container maxW="full"> |
|||
<Heading size="sm" py={4}> |
|||
Appearance |
|||
</Heading> |
|||
<RadioGroup onChange={setValue} value={value}> |
|||
<Stack> |
|||
<Radio value="system" colorScheme="teal" defaultChecked> |
|||
Use system settings (default) |
|||
</Radio> |
|||
<Radio value="light" colorScheme="teal"> |
|||
Light |
|||
</Radio> |
|||
<Radio value="dark" colorScheme="teal"> |
|||
Dark |
|||
</Radio> |
|||
</Stack> |
|||
</RadioGroup> |
|||
<Button colorScheme='teal' mt={4}>Save</Button> |
|||
</ Container> |
|||
</> |
|||
); |
|||
} |
|||
export default Appearance; |
@ -0,0 +1,34 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Box, Button, Container, FormControl, FormLabel, Heading, Input } from '@chakra-ui/react'; |
|||
|
|||
const ChangePassword: React.FC = () => { |
|||
|
|||
return ( |
|||
<> |
|||
<Container maxW="full"> |
|||
<Heading size="sm" py={4}> |
|||
Change Password |
|||
</Heading> |
|||
<Box as="form" display="flex" flexDirection="column" alignItems="start"> |
|||
<FormControl> |
|||
<FormLabel color="gray.700">Old password</FormLabel> |
|||
<Input placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel color="gray.700">New password</FormLabel> |
|||
<Input placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel color="gray.700">Confirm new password</FormLabel> |
|||
<Input placeholder='Password' type="password" /> |
|||
</FormControl> |
|||
<Button colorScheme='teal' mt={4} type="submit"> |
|||
Save |
|||
</Button> |
|||
</Box> |
|||
</ Container> |
|||
</> |
|||
); |
|||
} |
|||
export default ChangePassword; |
@ -0,0 +1,23 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Button, Container, Heading, Text } from '@chakra-ui/react'; |
|||
|
|||
const DeleteAccount: React.FC = () => { |
|||
|
|||
return ( |
|||
<> |
|||
<Container maxW="full"> |
|||
<Heading size="sm" py={4}> |
|||
Delete Account |
|||
</Heading> |
|||
<Text> |
|||
Are you sure you want to delete your account? This action cannot be undone. |
|||
</Text> |
|||
<Button colorScheme='red' mt={4}> |
|||
Delete |
|||
</Button> |
|||
</ Container> |
|||
</> |
|||
); |
|||
} |
|||
export default DeleteAccount; |
@ -0,0 +1,49 @@ |
|||
import React, { useState } from 'react'; |
|||
|
|||
import { Button, Container, FormControl, FormLabel, Heading, Input, Text } from '@chakra-ui/react'; |
|||
|
|||
import { useUserStore } from '../../store/user-store'; |
|||
|
|||
const UserInformation: React.FC = () => { |
|||
const [editMode, setEditMode] = useState(false); |
|||
const { user } = useUserStore(); |
|||
|
|||
|
|||
const toggleEditMode = () => { |
|||
setEditMode(!editMode); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<Container maxW="full"> |
|||
<Heading size="sm" py={4}> |
|||
User Information |
|||
</Heading> |
|||
<FormControl> |
|||
<FormLabel color="gray.700">Full name</FormLabel> |
|||
{ |
|||
editMode ? |
|||
<Input placeholder={user?.full_name || "Full name"} type="text" /> : |
|||
<Text> |
|||
{user?.full_name || "N/A"} |
|||
</Text> |
|||
} |
|||
</FormControl> |
|||
<FormControl mt={4}> |
|||
<FormLabel color="gray.700">Email</FormLabel> |
|||
{ |
|||
editMode ? |
|||
<Input placeholder={user?.email} type="text" /> : |
|||
<Text> |
|||
{user?.email || "N/A"} |
|||
</Text> |
|||
} |
|||
</FormControl> |
|||
<Button colorScheme='teal' mt={4} onClick={toggleEditMode}> |
|||
{editMode ? "Save" : "Edit"} |
|||
</Button> |
|||
</ Container> |
|||
</> |
|||
); |
|||
} |
|||
export default UserInformation; |
Loading…
Reference in new issue