theme-ui#Input TypeScript Examples
The following examples show how to use
theme-ui#Input.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: InputBox.tsx From slice-machine with Apache License 2.0 | 6 votes |
InputBox: React.FunctionComponent<InputBoxProps> = ({ name, label, placeholder, error, dataCy, }) => ( <Box mb={3}> <Label htmlFor={name} mb={2}> {label} </Label> <Field name={name} type="text" placeholder={placeholder} as={Input} autoComplete="off" {...(dataCy ? { "data-cy": dataCy } : null)} /> {error ? ( <Text data-cy={dataCy ? `${dataCy}-error` : "input-error"} sx={{ color: "error", mt: 1 }} > {error} </Text> ) : null} </Box> )
Example #2
Source File: create.tsx From slice-machine with Apache License 2.0 | 6 votes |
InputBox = ({ name, label, placeholder, error, }: { name: string; label: string; placeholder: string; error?: string; }) => ( <Box mb={3}> <Label htmlFor={name} mb={2}> {label} </Label> <Field name={name} type="text" placeholder={placeholder} as={Input} autoComplete="off" /> {error ? <Text sx={{ color: "error", mt: 1 }}>{error}</Text> : null} </Box> )
Example #3
Source File: update.tsx From slice-machine with Apache License 2.0 | 6 votes |
InputBox = ({
name,
label,
placeholder,
error,
...rest
}: {
name: string;
label: string;
placeholder: string;
error?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[x: string]: any;
}) => (
<Box mb={3}>
<Label htmlFor={name} mb={2}>
{label}
</Label>
<Field
name={name}
type="text"
placeholder={placeholder}
as={Input}
autoComplete="off"
{...rest}
/>
{error ? <Text sx={{ color: "error", mt: 1 }}>{error}</Text> : null}
</Box>
)
Example #4
Source File: Searchbar.tsx From nextjs-shopify with MIT License | 5 votes |
SearchModalContent = (props: {
initialSearch?: string
onSearch: (term: string) => any
}) => {
const [search, setSearch] = useState(
props.initialSearch && String(props.initialSearch)
)
const [products, setProducts] = useState([] as any[])
const [loading, setLoading] = useState(false)
const getProducts = async (searchTerm: string) => {
setLoading(true)
const results = await searchProducts(
shopifyConfig,
String(searchTerm),
)
setSearch(searchTerm)
setProducts(results)
setLoading(false)
if (searchTerm) {
props.onSearch(searchTerm)
}
}
useEffect(() => {
if (search) {
getProducts(search)
}
}, [])
const throttleSearch = useCallback(throttle(getProducts), [])
return (
<Themed.div
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
p: [1, 2],
width: '100%',
}}
>
<Input
type="search"
sx={{ marginBottom: 15 }}
defaultValue={props.initialSearch}
placeholder="Search for products..."
onChange={(event) => throttleSearch(event.target.value)}
/>
{loading ? (
<LoadingDots />
) : products.length ? (
<>
<Label>
Search Results for "<strong>{search}</strong>"
</Label>
<ProductGrid
cardProps={{
imgHeight: 540,
imgWidth: 540,
imgPriority: false,
}}
products={products}
offset={0}
limit={products.length}
></ProductGrid>
</>
) : (
<span>
{search ? (
<>
There are no products that match "<strong>{search}</strong>"
</>
) : (
<> </>
)}
</span>
)}
</Themed.div>
)
}
Example #5
Source File: AddComment.tsx From use-comments with MIT License | 5 votes |
AddComment = ({ onSubmit }: AddCommentProps) => {
const [username, setUsername] = useState('');
const [comment, setComment] = useState('');
const [added, setAdded] = useState(false);
return (
<Box
as="form"
onSubmit={e => {
console.log({ e });
e.preventDefault();
onSubmit({ content: comment, author: username });
setAdded(true);
setComment('');
setUsername('');
}}
>
<Label htmlFor="username">Username</Label>
<Input
name="username"
id="username"
placeholder="Jon Doe"
value={username}
onChange={e => setUsername(e.target.value)}
sx={{ mb: 3 }}
autoComplete="off"
/>
<Label htmlFor="comment">Comment</Label>
<Textarea
name="comment"
id="comment"
rows={2}
placeholder="Tell me what you think ?"
value={comment}
onChange={e => setComment(e.target.value)}
sx={{ mb: 3, fontFamily: 'body' }}
/>
<Button
type="submit"
sx={{
mb: 3,
...((!username || !comment) && {
pointerEvents: 'none',
opacity: '0.5',
}),
}}
disabled={!username || !comment}
>
Add comment
</Button>
{added && (
<Message
variant="primary"
sx={{
fontSize: '0.8em',
}}
>
Thanks for your comment! ? Your comment status is{' '}
<i>waiting for approval</i>. Comments on this website need to be
approved before they are visible to others.
</Message>
)}
<Divider />
</Box>
);
}
Example #6
Source File: CartItem.tsx From nextjs-shopify with MIT License | 4 votes |
CartItem = ({
item,
currencyCode,
}: {
item: /*ShopifyBuy.LineItem todo: check if updated types*/ any
currencyCode: string
}) => {
const updateItem = useUpdateItemQuantity()
const removeItem = useRemoveItemFromCart()
const [quantity, setQuantity] = useState(item.quantity)
const [removing, setRemoving] = useState(false)
const updateQuantity = async (quantity: number) => {
await updateItem(item.variant.id, quantity)
}
const handleQuantity = (e: ChangeEvent<HTMLInputElement>) => {
const val = Number(e.target.value)
if (Number.isInteger(val) && val >= 0) {
setQuantity(val)
}
}
const handleBlur = () => {
const val = Number(quantity)
if (val !== item.quantity) {
updateQuantity(val)
}
}
const increaseQuantity = (n = 1) => {
const val = Number(quantity) + n
if (Number.isInteger(val) && val >= 0) {
setQuantity(val)
updateQuantity(val)
}
}
const handleRemove = async () => {
setRemoving(true)
try {
// If this action succeeds then there's no need to do `setRemoving(true)`
// because the component will be removed from the view
await removeItem(item.variant.id)
} catch (error) {
console.error(error)
setRemoving(false)
}
}
useEffect(() => {
// Reset the quantity state if the item quantity changes
if (item.quantity !== Number(quantity)) {
setQuantity(item.quantity)
}
}, [item.quantity])
return (
<Grid gap={2} sx={{ width: '100%', m: 12 }} columns={[2]}>
<div
sx={{
padding: 1,
border: '1px solid gray',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Image
height={130}
width={130}
unoptimized
alt={item.variant.image.altText}
src={item.variant.image.src}
/>
</div>
<div>
<Themed.div
as={Link}
href={`/product/${item.variant.product.handle}/`}
sx={{ fontSize: 3, m: 0, fontWeight: 700 }}
>
<>
{item.title}
<Text
sx={{
fontSize: 4,
fontWeight: 700,
display: 'block',
marginLeft: 'auto',
}}
>
{getPrice(
item.variant.priceV2.amount,
item.variant.priceV2.currencyCode || 'USD'
)}
</Text>
</>
</Themed.div>
<Themed.ul sx={{ mt: 2, mb: 0, padding: 0, listStyle: 'none' }}>
<li>
<div sx={{ display: 'flex', justifyItems: 'center' }}>
<IconButton onClick={() => increaseQuantity(-1)}>
<Minus width={18} height={18} />
</IconButton>
<label>
<Input
sx={{
height: '100%',
textAlign: 'center',
}}
type="number"
max={99}
min={0}
value={quantity}
onChange={handleQuantity}
onBlur={handleBlur}
/>
</label>
<IconButton onClick={() => increaseQuantity(1)}>
<Plus width={18} height={18} />
</IconButton>
</div>
</li>
{item.variant.selectedOptions.map((option: any) => (
<li key={option.value}>
{option.name}:{option.value}
</li>
))}
</Themed.ul>
</div>
</Grid>
)
}
Example #7
Source File: ChatFooter.tsx From chat-window with MIT License | 4 votes |
ChatFooter = ({
placeholder,
emailInputPlaceholder,
isSending,
shouldRequireEmail,
accountId,
baseUrl,
onSendMessage,
}: {
placeholder?: string;
emailInputPlaceholder?: string;
isSending: boolean;
shouldRequireEmail?: boolean;
accountId: string;
baseUrl?: string;
onSendMessage: (message: Partial<Message>, email?: string) => Promise<void>;
}) => {
const [message, setMessage] = React.useState('');
const [email, setEmail] = React.useState('');
const [isUploading, setIsUploading] = React.useState(false);
const [error, setError] = React.useState<any>(null);
const messageInput = React.useRef(null);
const hasValidEmail = email && email.length > 5 && email.indexOf('@') !== -1;
const isDisabled = isUploading || isSending;
const handleMessageChange = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
setMessage(e.target.value);
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) =>
setEmail(e.target.value);
const handleSetEmail = (e?: React.FormEvent<HTMLFormElement>) => {
e && e.preventDefault();
if (messageInput.current) {
messageInput.current.focus();
}
};
const handleSendMessage = (e?: React.FormEvent<HTMLFormElement>) => {
e && e.preventDefault();
onSendMessage({body: message}, email);
setMessage('');
setEmail('');
};
const handleUploadStarted = () => setIsUploading(true);
const handleUploadError = (err: any) => {
setError(err);
setIsUploading(false);
};
const handleUploadSuccess = ({data: file}: {data: Attachment}) => {
if (file && file.id) {
onSendMessage({body: message, file_ids: [file.id]}, email);
setMessage('');
setEmail('');
setIsUploading(false);
setError(null);
}
};
const handleKeyDown = (e: any) => {
const {key, shiftKey} = e;
if (!shiftKey && key === 'Enter') {
handleSendMessage(e);
}
};
return (
<Box>
<form onSubmit={handleSetEmail}>
{shouldRequireEmail && (
<Box py={1} sx={{borderBottom: '1px solid rgb(230, 230, 230)'}}>
<Input
sx={{variant: 'styles.input.transparent'}}
placeholder={emailInputPlaceholder}
value={email}
onChange={handleEmailChange}
/>
</Box>
)}
</form>
<form onSubmit={handleSendMessage}>
<Flex sx={{alignItems: 'center'}} py={2}>
<Box mr={2} sx={{flex: 1}}>
<ResizableTextArea
sx={{
fontFamily: 'body',
color: 'input',
variant: 'styles.input.transparent',
}}
ref={messageInput}
className="TextArea--transparent"
placeholder={placeholder}
minRows={1}
maxRows={4}
autoFocus
value={message}
disabled={isDisabled || (shouldRequireEmail && !hasValidEmail)}
onKeyDown={handleKeyDown}
onChange={handleMessageChange}
/>
</Box>
<Flex>
<Upload
action={`${baseUrl}/api/upload`}
data={{account_id: accountId}}
headers={{'X-Requested-With': null}}
onStart={handleUploadStarted}
onSuccess={handleUploadSuccess}
onError={handleUploadError}
>
<Button
variant="link"
type="button"
disabled={isDisabled}
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '50%',
height: '36px',
width: '36px',
padding: 0,
}}
>
<PaperclipIcon
width={16}
height={16}
fill={error ? 'red' : 'gray'}
/>
</Button>
</Upload>
<Button
variant="primary"
type="submit"
disabled={isDisabled}
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '50%',
height: '36px',
width: '36px',
padding: 0,
}}
>
<SendIcon width={16} height={16} fill="background" />
</Button>
</Flex>
</Flex>
</form>
</Box>
);
}
Example #8
Source File: EmailForm.tsx From chat-window with MIT License | 4 votes |
EmailForm = ({
newMessagePlaceholder,
emailInputPlaceholder,
isSending,
onSendMessage,
}: Props) => {
const [message, setMessage] = React.useState('');
const [email, setEmail] = React.useState('');
const hasValidEmail = email && email.length > 5 && email.indexOf('@') !== -1;
const hasValidMessage = message && message.trim().length > 0;
const isDisabled = !!isSending || !hasValidEmail || !hasValidMessage;
const handleMessageChange = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
setMessage(e.target.value);
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) =>
setEmail(e.target.value);
const handleSendMessage = (e?: any) => {
e && e.preventDefault();
onSendMessage({body: message}, email);
setMessage('');
setEmail('');
};
const handleKeyDown = (e: any) => {
const {key, shiftKey} = e;
if (!shiftKey && key === 'Enter') {
handleSendMessage(e);
}
};
return (
<Flex
py={2}
px={3}
sx={{
flex: 1,
flexDirection: 'column',
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 21px 4px -20px inset',
overflowY: 'scroll',
}}
>
<Box py={1} sx={{borderBottom: '1px solid rgb(230, 230, 230)'}}>
<Input
sx={{variant: 'styles.input.transparent'}}
placeholder={emailInputPlaceholder || '[email protected]'}
autoFocus
value={email}
onChange={handleEmailChange}
/>
</Box>
<Box py={2} sx={{flex: 1}}>
<ResizableTextArea
sx={{
fontFamily: 'body',
color: 'input',
variant: 'styles.input.transparent',
}}
className="TextArea--transparent"
placeholder={newMessagePlaceholder || 'Write your message...'}
value={message}
onKeyDown={handleKeyDown}
onChange={handleMessageChange}
/>
</Box>
<Flex sx={{justifyContent: 'flex-end'}}>
<Button
variant="link"
type="submit"
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '50%',
height: '36px',
width: '36px',
padding: 0,
}}
onClick={handleSendMessage}
>
<SendIcon
width={16}
height={16}
fill={isDisabled ? 'muted' : 'primary'}
/>
</Button>
</Flex>
</Flex>
);
}
Example #9
Source File: VariationModal.tsx From slice-machine with Apache License 2.0 | 4 votes |
VariationModal: React.FunctionComponent<{
isOpen: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onClose: () => any;
onSubmit: (
id: string,
name: string,
copiedVariation: Models.VariationSM
) => void;
initialVariation: Models.VariationSM;
variations: ReadonlyArray<Models.VariationSM>;
}> = ({ isOpen, onClose, onSubmit, initialVariation, variations }) => {
const [errors, setErrors] = useState<{ [fieldKey: string]: string }>({});
const [generatedId, setGeneratedId] = useState<string>("");
const [isGeneratedFromName, setIsGeneratedFromName] = useState<boolean>(true);
const [name, setName] = useState<string>("");
const [origin, setOrigin] = useState<{ value: string; label: string }>({
value: initialVariation.id,
label: initialVariation.name,
});
function validateForm({
id,
name,
origin,
}: {
id?: string;
name?: string;
origin: { value: string };
}) {
const idError = !(id && id.length) ? { id: "Required!" } : null;
const existingIdError = variations.find((v) => v.id === id)
? { id: "This id already exists!" }
: null;
const nameError = !(name && name.length) ? { name: "Required!" } : null;
const originError = !(
origin.value.length && variations.find((v) => v.id === origin.value)
)
? { id: "Yuu must select an existing variation!" }
: null;
const invalidIdError = id &&
id.length &&
!/^[A-Za-z0-9]+([A-Za-z0-9]+)*$/.exec(id) && {
id: "No special characters allowed",
};
return {
...idError,
...existingIdError,
...nameError,
...originError,
...invalidIdError,
};
}
function generateId(str: string) {
const slug = Variation.generateId(str);
setGeneratedId(slug);
}
function changeName(str: string) {
setName(str);
if (isGeneratedFromName) generateId(str);
}
function changeId(str: string) {
setIsGeneratedFromName(false);
generateId(str);
}
function handleClose() {
reset();
onClose();
}
function reset() {
setGeneratedId("");
setName("");
setErrors({});
setIsGeneratedFromName(true);
setOrigin({ value: initialVariation.id, label: initialVariation.name });
}
useEffect(() => {
reset();
}, [initialVariation, isOpen]);
// eslint-disable-next-line @typescript-eslint/require-await
async function handleSubmit() {
const data = { id: generatedId, name, origin };
const errors = validateForm(data);
if (Object.keys(errors).length) setErrors(errors);
else {
const copiedVariation = variations.find((v) => v.id === origin.value);
if (copiedVariation) {
onSubmit(generatedId, name, copiedVariation);
handleClose();
}
}
}
return (
<SliceMachineModal
isOpen={isOpen}
shouldCloseOnOverlayClick
onRequestClose={() => handleClose()}
contentLabel="Widget Form Modal"
style={{
content: {
maxWidth: "700px",
},
}}
>
<Formik
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
initialValues={{ id: generatedId, name, origin } as any}
onSubmit={handleSubmit}
>
<Form
id={"variation-add"}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
handleSubmit();
}
}}
>
<Box>
<Card
sx={{ textAlign: "left" }}
HeaderContent={<Text as="h2">Add new Variation</Text>}
FooterContent={
<Flex sx={{ justifyContent: "flex-end" }}>
<Button onClick={handleClose} mr={2} variant="secondary">
Cancel
</Button>
<Button type="submit">Submit</Button>
</Flex>
}
close={handleClose}
>
<Box sx={{ pb: 4, mt: 4 }}>
<Label htmlFor="name" sx={{ mb: 1 }}>
Variation name*
{errors.name ? <Error msg={errors.name} /> : ""}
</Label>
<Field
autoComplete="off"
id="name"
name="name"
placeholder="e.g. Grid - With Icon"
as={Input}
maxLength={30}
value={name}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
changeName(e.currentTarget.value)
}
/>
<Text>
It will appear here in Slice Machine, and in the page editor
in Prismic
</Text>
</Box>
<Box sx={{ pb: 4 }}>
<Label htmlFor="id" sx={{ mb: 1 }}>
Variation ID*{errors.id ? <Error msg={errors.id} /> : ""}
</Label>
<Field
autoComplete="off"
id="id"
name="id"
placeholder="e.g. GridWithIcon"
as={Input}
maxLength={30}
value={generatedId}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
changeId(e.currentTarget.value)
}
/>
<Text>
It's generated automatically based on the variation name and
will appear in the API responses.
</Text>
</Box>
<Box sx={{ pb: 4 }}>
<Label htmlFor="origin" sx={{ mb: 1 }}>
Duplicate from
</Label>
<Select
name="origin"
options={variations.map((v) => ({
value: v.id,
label: v.name,
}))}
onChange={(v: { label: string; value: string } | null) => {
if (v) setOrigin(v);
}}
defaultValue={origin}
maxMenuHeight={150}
theme={(theme) => {
return {
...theme,
colors: {
...theme.colors,
text: "text",
primary: "background",
},
};
}}
/>
</Box>
</Card>
</Box>
</Form>
</Formik>
</SliceMachineModal>
);
}
Example #10
Source File: Token.tsx From nft-market with MIT License | 4 votes |
Token = ({ token, isOnSale, onTransfer, onBuy, onSale }: TokenCompProps) => {
const [transfer, setTransfer] = useState<boolean>(false)
const [onSaleActive, setOnSale] = useState<boolean>(false)
const [address, setAddress] = useState<string>('')
const [price, setPrice] = useState<string>('')
const { user, ethPrice, contractDetails, transferToken, buyToken, setTokenSale } = useAppState()
const onTransferClick = async (e: FormEvent | MouseEvent) => {
e.preventDefault()
if (onTransfer && utils.isAddress(address)) {
transferToken(token.id, address)
setTransfer(false)
}
}
const onBuyClick = (e: MouseEvent) => {
e.preventDefault()
onBuy && buyToken(token.id, token.price)
}
const onSaleClick = async (e: MouseEvent) => {
e.preventDefault()
if (!onSale) return
try {
await setTokenSale(token.id, utils.parseEther(price), true)
setOnSale(false)
} catch (e) {
throw e
}
}
const { data: owner } = useSWR(token.id, fetchOwner)
const { data } = useSWR(`${METADATA_API}/token/${token.id}`, fetcherMetadata)
const tokenPriceEth = formatPriceEth(token.price, ethPrice)
if (!data)
return (
<Card variant="nft">
<Spinner />
</Card>
)
if (!data.name) return null
return (
<Card variant="nft">
<Image
sx={{ width: '100%', bg: 'white', borderBottom: '1px solid black' }}
src={data.image}
/>
<Box p={3} pt={2}>
<Heading as="h2">{data.name}</Heading>
<Divider variant="divider.nft" />
<Box>
<Text sx={{ color: 'lightBlue', fontSize: 1, fontWeight: 'bold' }}>Price</Text>
<Heading as="h3" sx={{ color: 'green', m: 0, fontWeight: 'bold' }}>
{constants.EtherSymbol} {Number(utils.formatEther(token.price)).toFixed(2)}{' '}
<Text sx={{ color: 'navy' }} as="span" variant="text.body">
({tokenPriceEth})
</Text>
</Heading>
{owner && typeof owner === 'string' && !onTransfer && (
<Box mt={2}>
<Text as="p" sx={{ color: 'lightBlue', fontSize: 1, fontWeight: 'bold' }}>
Owner
</Text>
<NavLink
target="_blank"
href={`https://rinkeby.etherscan.io/address/${owner}`}
variant="owner"
style={{
textOverflow: 'ellipsis',
width: '100%',
position: 'relative',
overflow: 'hidden',
}}
>
{toShort(owner)}
</NavLink>
</Box>
)}
<Box mt={2}>
<NavLink
target="_blank"
href={`https://testnets.opensea.io/assets/${contractDetails?.address}/${token.id}`}
variant="openSea"
>
View on Opensea.io
</NavLink>
</Box>
</Box>
{onTransfer && (
<Flex mt={3} sx={{ justifyContent: 'center' }}>
{transfer && (
<Box sx={{ width: '100%' }}>
<Flex
onSubmit={onTransferClick}
sx={{ width: '100%', flexDirection: 'column' }}
as="form"
>
<Input
onChange={e => setAddress(e.currentTarget.value)}
placeholder="ETH Address 0x0..."
/>
</Flex>
<Flex mt={2}>
<Button sx={{ bg: 'green' }} onClick={onTransferClick} variant="quartiary">
Confirm
</Button>
<Button
sx={{ bg: 'red' }}
ml={2}
onClick={() => setTransfer(false)}
variant="quartiary"
>
Cancel
</Button>
</Flex>
</Box>
)}
{onSaleActive && (
<Box sx={{ width: '100%' }}>
<Flex
onSubmit={onTransferClick}
sx={{ width: '100%', flexDirection: 'column' }}
as="form"
>
<Input
onChange={e => setPrice(e.currentTarget.value)}
placeholder="Token Price in ETH"
/>
</Flex>
<Flex mt={2}>
<Button sx={{ bg: 'green' }} onClick={onSaleClick} variant="quartiary">
Confirm
</Button>
<Button
sx={{ bg: 'red' }}
ml={2}
onClick={() => setOnSale(false)}
variant="quartiary"
>
Cancel
</Button>
</Flex>
</Box>
)}
{!transfer && !onSaleActive && (
<Flex sx={{ flexDirection: 'column', width: '100%', justifyContent: 'center' }}>
<Button onClick={() => setTransfer(!transfer)} variant="tertiary">
Transfer
</Button>
{isOnSale ? (
<Button
mt={2}
onClick={() => onSale && setTokenSale(token.id, token.price, false)}
variant="tertiary"
>
Remove from Sale
</Button>
) : (
<Button mt={2} onClick={() => setOnSale(!onSaleActive)} variant="tertiary">
Put Token for Sale
</Button>
)}
</Flex>
)}
</Flex>
)}
{onBuy && (
<Flex mt={3} sx={{ justifyContent: 'center', width: '100%' }}>
<Button
sx={{
opacity: !!user?.ownedTokens.find(
a => utils.formatUnits(a.id) === utils.formatUnits(token.id)
)
? 0.5
: 1,
pointerEvents: !!user?.ownedTokens.find(
a => utils.formatUnits(a.id) === utils.formatUnits(token.id)
)
? 'none'
: 'visible',
}}
onClick={onBuyClick}
variant="quartiary"
>
Buy Token
</Button>
</Flex>
)}
</Box>
</Card>
)
}