Add user account page
This commit is contained in:
24
apps/builder/components/account/AccountHeader.tsx
Normal file
24
apps/builder/components/account/AccountHeader.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { Flex } from '@chakra-ui/react'
|
||||
import { TypebotLogo } from 'assets/logos'
|
||||
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
|
||||
import React from 'react'
|
||||
|
||||
export const AccountHeader = () => (
|
||||
<Flex w="full" borderBottomWidth="1px" justify="center">
|
||||
<Flex
|
||||
justify="space-between"
|
||||
alignItems="center"
|
||||
h="16"
|
||||
maxW="1000px"
|
||||
flex="1"
|
||||
>
|
||||
<NextChakraLink
|
||||
className="w-24"
|
||||
href="/typebots"
|
||||
data-testid="authenticated"
|
||||
>
|
||||
<TypebotLogo w="30px" />
|
||||
</NextChakraLink>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)
|
27
apps/builder/components/account/BillingSection.tsx
Normal file
27
apps/builder/components/account/BillingSection.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { Stack, Heading, HStack, Button, Text } from '@chakra-ui/react'
|
||||
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import React from 'react'
|
||||
import { SubscriptionTag } from './SubscriptionTag'
|
||||
|
||||
export const BillingSection = () => {
|
||||
const { user } = useUser()
|
||||
return (
|
||||
<Stack direction="row" spacing="10" justifyContent={'space-between'}>
|
||||
<Heading as="h2" fontSize="xl">
|
||||
Billing
|
||||
</Heading>
|
||||
<Stack spacing="6" w="400px">
|
||||
<HStack>
|
||||
<Text>Your subscription</Text>
|
||||
<SubscriptionTag plan={user?.plan} />
|
||||
</HStack>
|
||||
{user?.stripeId && (
|
||||
<Button as={NextChakraLink} href="test">
|
||||
Billing portal
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
116
apps/builder/components/account/PersonalInfoForm.tsx
Normal file
116
apps/builder/components/account/PersonalInfoForm.tsx
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
Stack,
|
||||
Heading,
|
||||
HStack,
|
||||
Avatar,
|
||||
Button,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Input,
|
||||
Tooltip,
|
||||
Flex,
|
||||
Text,
|
||||
} from '@chakra-ui/react'
|
||||
import { UploadIcon } from 'assets/icons'
|
||||
import { UploadButton } from 'components/shared/buttons/UploadButton'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import React, { ChangeEvent, useState } from 'react'
|
||||
import { uploadFile } from 'services/utils'
|
||||
|
||||
export const PersonalInfoForm = () => {
|
||||
const {
|
||||
user,
|
||||
updateUser,
|
||||
saveUser,
|
||||
hasUnsavedChanges,
|
||||
isSaving,
|
||||
isOAuthProvider,
|
||||
} = useUser()
|
||||
const [reloadParam, setReloadParam] = useState('')
|
||||
const [isUploading, setIsUploading] = useState(false)
|
||||
|
||||
const handleFileChange = async (file: File) => {
|
||||
setIsUploading(true)
|
||||
const { url } = await uploadFile(file, `${user?.id}/avatar`)
|
||||
setReloadParam(Date.now().toString())
|
||||
updateUser({ image: url })
|
||||
setIsUploading(false)
|
||||
}
|
||||
|
||||
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
updateUser({ name: e.target.value })
|
||||
}
|
||||
|
||||
const handleEmailChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
updateUser({ email: e.target.value })
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack direction="row" spacing="10" justifyContent={'space-between'}>
|
||||
<Heading as="h2" fontSize="xl">
|
||||
Personal info
|
||||
</Heading>
|
||||
<Stack spacing="6" w="400px">
|
||||
<HStack spacing={6}>
|
||||
<Avatar
|
||||
size="lg"
|
||||
src={user?.image ? `${user.image}?${reloadParam}` : undefined}
|
||||
name={user?.name ?? undefined}
|
||||
/>
|
||||
<Stack>
|
||||
<UploadButton
|
||||
size="sm"
|
||||
leftIcon={<UploadIcon />}
|
||||
isLoading={isUploading}
|
||||
onUploadChange={handleFileChange}
|
||||
>
|
||||
Change photo
|
||||
</UploadButton>
|
||||
<Text color="gray.500" fontSize="sm">
|
||||
.jpg or.png, max 1MB
|
||||
</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel htmlFor="name">Name</FormLabel>
|
||||
<Input
|
||||
id="name"
|
||||
value={user?.name ?? ''}
|
||||
onChange={handleNameChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<Tooltip
|
||||
label="Can't update the email because it is linked to an OAuth service"
|
||||
placement="left"
|
||||
hasArrow
|
||||
isDisabled={!isOAuthProvider}
|
||||
>
|
||||
<FormControl>
|
||||
<FormLabel
|
||||
htmlFor="email"
|
||||
color={isOAuthProvider ? 'gray.500' : 'current'}
|
||||
>
|
||||
Email address
|
||||
</FormLabel>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
isDisabled={isOAuthProvider}
|
||||
value={user?.email ?? ''}
|
||||
onChange={handleEmailChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
|
||||
{hasUnsavedChanges && (
|
||||
<Flex justifyContent="flex-end">
|
||||
<Button colorScheme="blue" onClick={saveUser} isLoading={isSaving}>
|
||||
Save
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
22
apps/builder/components/account/SubscriptionTag.tsx
Normal file
22
apps/builder/components/account/SubscriptionTag.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Tag } from '@chakra-ui/react'
|
||||
import { Plan } from 'db'
|
||||
|
||||
export const SubscriptionTag = ({ plan }: { plan?: Plan }) => {
|
||||
switch (plan) {
|
||||
case Plan.FREE: {
|
||||
return <Tag>Free plan</Tag>
|
||||
}
|
||||
case Plan.LIFETIME: {
|
||||
return <Tag colorScheme="yellow">Lifetime plan</Tag>
|
||||
}
|
||||
case Plan.OFFERED: {
|
||||
return <Tag>Offered</Tag>
|
||||
}
|
||||
case Plan.PRO: {
|
||||
return <Tag colorScheme="blue">Pro plan</Tag>
|
||||
}
|
||||
default: {
|
||||
return <Tag>Free plan</Tag>
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user