-
Notifications
You must be signed in to change notification settings - Fork 198
feat: referral dashboard and registering #11377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
00d3ffa
2f019cb
aebb886
49ee79b
85ad443
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import { Button, Card, CardBody, CardHeader, Heading, HStack, Input } from '@chakra-ui/react' | ||
| import { FaPlus } from 'react-icons/fa' | ||
| import { useTranslate } from 'react-polyglot' | ||
|
|
||
| type CreateCodeCardProps = { | ||
| newCodeInput: string | ||
| isCreating: boolean | ||
| onInputChange: (value: string) => void | ||
| onGenerateRandom: () => void | ||
| onCreate: () => void | ||
| } | ||
|
|
||
| export const CreateCodeCard = ({ | ||
| newCodeInput, | ||
| isCreating, | ||
| onInputChange, | ||
| onGenerateRandom, | ||
| onCreate, | ||
| }: CreateCodeCardProps) => { | ||
| const translate = useTranslate() | ||
|
|
||
| return ( | ||
| <Card | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| py={2} | ||
| > | ||
| <CardHeader> | ||
| <Heading size='md'>{translate('referral.createNewCode')}</Heading> | ||
| </CardHeader> | ||
| <CardBody> | ||
| <HStack> | ||
| <Input | ||
| value={newCodeInput} | ||
| onChange={e => onInputChange(e.target.value.toUpperCase())} | ||
| placeholder={translate('referral.enterCodeOrLeaveEmpty')} | ||
| maxLength={20} | ||
| bg='background.surface.raised.base' | ||
| border='none' | ||
| /> | ||
| <Button | ||
| onClick={onGenerateRandom} | ||
| leftIcon={<FaPlus />} | ||
| variant='outline' | ||
| flexShrink={0} | ||
| borderRadius='full' | ||
| border='1px solid' | ||
| borderColor='gray.700' | ||
| backgroundColor='background.surface.raised.base' | ||
| > | ||
| {translate('referral.random')} | ||
| </Button> | ||
| <Button | ||
| onClick={onCreate} | ||
| colorScheme='blue' | ||
| isLoading={isCreating} | ||
| flexShrink={0} | ||
| borderRadius='full' | ||
| > | ||
| {translate('referral.create')} | ||
| </Button> | ||
| </HStack> | ||
|
Comment on lines
+13
to
+64
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sanitize referral-code input to expected charset (avoid create failures on spaces/symbols) import { FaPlus } from 'react-icons/fa'
import { useTranslate } from 'react-polyglot'
+const normalizeReferralCodeInput = (value: string): string => {
+ return value.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 20)
+}
+
type CreateCodeCardProps = {
newCodeInput: string
isCreating: boolean
onInputChange: (value: string) => void
@@
<Input
value={newCodeInput}
- onChange={e => onInputChange(e.target.value.toUpperCase())}
+ onChange={e => onInputChange(normalizeReferralCodeInput(e.target.value))}
placeholder={translate('referral.enterCodeOrLeaveEmpty')}
maxLength={20}
bg='background.surface.raised.base'
border='none'
/>🤖 Prompt for AI Agents |
||
| </CardBody> | ||
| </Card> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Card, CardBody, Flex, Heading, IconButton, Skeleton, Text } from '@chakra-ui/react' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FaCopy } from 'react-icons/fa' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FaXTwitter } from 'react-icons/fa6' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useTranslate } from 'react-polyglot' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type ReferralCodeCardProps = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: string | null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShareOnX: (code: string) => void | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onCopyCode: (code: string) => void | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const ReferralCodeCard = ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShareOnX, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onCopyCode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: ReferralCodeCardProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const translate = useTranslate() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isLoading) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Card | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| color='white' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius='2xl' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| overflow='hidden' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| width='50%' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderTop='1px solid' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderColor='gray.700' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardBody px={6} py={4} display='flex' alignItems='center'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Skeleton height='60px' width='full' /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </CardBody> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Card> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Card | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| color='white' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius='2xl' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| overflow='hidden' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| width='50%' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderTop='1px solid' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderColor='gray.700' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardBody px={6} py={4} display='flex' alignItems='center'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Flex alignItems='center' justifyContent='space-between' width='full'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Flex flexDirection='column' gap={0}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Text fontSize='md' opacity={0.7} mb={1}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {translate('referral.yourReferralCode')} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Heading size='xl' fontWeight='bold' letterSpacing='wide'> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {code || 'N/A'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use translation key for fallback text. The hardcoded 'N/A' should use a translation key for i18n support. As per coding guidelines, all copy/text must use translation keys. - {code || 'N/A'}
+ {code || translate('common.notAvailable')}Note: You may need to add
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Heading> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Flex> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {code && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Flex alignItems='center' gap={2}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <IconButton | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| aria-label='Share on X' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| icon={<FaXTwitter />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size='md' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colorScheme='whiteAlpha' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius='100%' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bg='whiteAlpha.200' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => onShareOnX(code)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <IconButton | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| aria-label='Copy link' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| icon={<FaCopy />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size='md' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colorScheme='whiteAlpha' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bg='whiteAlpha.200' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius='100%' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => onCopyCode(code)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+59
to
+76
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use translation keys for aria-labels. The aria-labels are hardcoded in English, which affects accessibility for non-English users. As per coding guidelines, all text should use translation keys. <IconButton
- aria-label='Share on X'
+ aria-label={translate('common.shareOnX')}
icon={<FaXTwitter />}
size='md'
colorScheme='whiteAlpha'
borderRadius='100%'
bg='whiteAlpha.200'
onClick={() => onShareOnX(code)}
/>
<IconButton
- aria-label='Copy link'
+ aria-label={translate('common.copy')}
icon={<FaCopy />}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tbh we don't care about aria-labels so meh
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gomesalexandre, understood! I'll skip aria-label suggestions for this codebase going forward. 🧠 Learnings used |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Flex> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Flex> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </CardBody> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Card> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀