kopia lustrzana https://github.com/bugout-dev/moonstream
commit
0daa60319a
backend/moonstream
frontend
src
Theme/Tooltip
|
@ -71,6 +71,13 @@ This CLI is configured to work with the following API URLs:
|
|||
type=str,
|
||||
help="Detailed description of the subscription type",
|
||||
)
|
||||
parser_subscription_types_create.add_argument(
|
||||
"-c",
|
||||
"--choices",
|
||||
nargs="*",
|
||||
help="Available subscription options for from builder.",
|
||||
required=True,
|
||||
)
|
||||
parser_subscription_types_create.add_argument(
|
||||
"--icon",
|
||||
required=True,
|
||||
|
@ -146,6 +153,13 @@ This CLI is configured to work with the following API URLs:
|
|||
type=str,
|
||||
help="Detailed description of the subscription type",
|
||||
)
|
||||
parser_subscription_types_update.add_argument(
|
||||
"-c",
|
||||
"--choices",
|
||||
nargs="*",
|
||||
help="Available subscription options for form builder.",
|
||||
required=False,
|
||||
)
|
||||
parser_subscription_types_update.add_argument(
|
||||
"--icon",
|
||||
required=False,
|
||||
|
|
|
@ -20,6 +20,7 @@ CANONICAL_SUBSCRIPTION_TYPES = {
|
|||
"ethereum_blockchain": SubscriptionTypeResourceData(
|
||||
id="ethereum_blockchain",
|
||||
name="Ethereum transactions",
|
||||
choices=["input:address", "tag:erc721"],
|
||||
description="Transactions that have been mined into the Ethereum blockchain",
|
||||
icon_url="https://s3.amazonaws.com/static.simiotics.com/moonstream/assets/ethereum/eth-diamond-purple.png",
|
||||
stripe_product_id=None,
|
||||
|
@ -30,6 +31,7 @@ CANONICAL_SUBSCRIPTION_TYPES = {
|
|||
id="ethereum_whalewatch",
|
||||
name="Ethereum whale watch",
|
||||
description="Ethereum accounts that have experienced a lot of recent activity",
|
||||
choices=[],
|
||||
# Icon taken from: https://www.maxpixel.net/Whale-Cetacean-Wildlife-Symbol-Ocean-Sea-Black-99310
|
||||
icon_url="https://s3.amazonaws.com/static.simiotics.com/moonstream/assets/whalewatch.png",
|
||||
stripe_product_id=None,
|
||||
|
@ -40,6 +42,7 @@ CANONICAL_SUBSCRIPTION_TYPES = {
|
|||
id="ethereum_txpool",
|
||||
name="Ethereum transaction pool",
|
||||
description="Transactions that have been submitted into the Ethereum transaction pool but not necessarily mined yet",
|
||||
choices=["input:address", "tag:erc721"],
|
||||
icon_url="https://s3.amazonaws.com/static.simiotics.com/moonstream/assets/ethereum/eth-diamond-rainbow.png",
|
||||
stripe_product_id=None,
|
||||
stripe_price_id=None,
|
||||
|
@ -74,6 +77,7 @@ def create_subscription_type(
|
|||
name: str,
|
||||
description: str,
|
||||
icon_url: str,
|
||||
choices: List[str] = [],
|
||||
stripe_product_id: Optional[str] = None,
|
||||
stripe_price_id: Optional[str] = None,
|
||||
active: bool = False,
|
||||
|
@ -111,6 +115,7 @@ def create_subscription_type(
|
|||
"id": id,
|
||||
"name": name,
|
||||
"description": description,
|
||||
"choices": choices,
|
||||
"icon_url": icon_url,
|
||||
"stripe_product_id": stripe_product_id,
|
||||
"stripe_price_id": stripe_price_id,
|
||||
|
@ -135,6 +140,7 @@ def cli_create_subscription_type(args: argparse.Namespace) -> None:
|
|||
args.name,
|
||||
args.description,
|
||||
args.icon,
|
||||
args.choices,
|
||||
args.stripe_product_id,
|
||||
args.stripe_price_id,
|
||||
args.active,
|
||||
|
@ -220,6 +226,7 @@ def update_subscription_type(
|
|||
id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
choices: Optional[List[str]] = None,
|
||||
icon_url: Optional[str] = None,
|
||||
stripe_product_id: Optional[str] = None,
|
||||
stripe_price_id: Optional[str] = None,
|
||||
|
@ -254,6 +261,8 @@ def update_subscription_type(
|
|||
updated_resource_data["name"] = name
|
||||
if description is not None:
|
||||
updated_resource_data["description"] = description
|
||||
if choices is not None:
|
||||
updated_resource_data["choices"] = choices
|
||||
if icon_url is not None:
|
||||
updated_resource_data["icon_url"] = icon_url
|
||||
if stripe_product_id is not None:
|
||||
|
@ -266,19 +275,15 @@ def update_subscription_type(
|
|||
# TODO(zomglings): This was written with an outdated bugout-python client.
|
||||
# New client has an update_resource method which is what we should be using
|
||||
# here.
|
||||
new_resource = bc.create_resource(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
application_id=MOONSTREAM_APPLICATION_ID,
|
||||
resource_data=updated_resource_data,
|
||||
timeout=BUGOUT_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
|
||||
try:
|
||||
bc.delete_resource(
|
||||
new_resource = bc.update_resource(
|
||||
token=MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||
resource_id=brood_resource_id,
|
||||
resource_data={"update": updated_resource_data},
|
||||
timeout=BUGOUT_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
raise ConflictingSubscriptionTypesError(
|
||||
f"Unable to delete old subscription type with ID: {id}. Error:\n{repr(e)}"
|
||||
|
@ -295,6 +300,7 @@ def cli_update_subscription_type(args: argparse.Namespace) -> None:
|
|||
args.id,
|
||||
args.name,
|
||||
args.description,
|
||||
args.choices,
|
||||
args.icon,
|
||||
args.stripe_product_id,
|
||||
args.stripe_price_id,
|
||||
|
@ -366,6 +372,20 @@ def ensure_canonical_subscription_types() -> BugoutResources:
|
|||
canonical_subscription_type.name,
|
||||
canonical_subscription_type.description,
|
||||
canonical_subscription_type.icon_url,
|
||||
canonical_subscription_type.choices,
|
||||
canonical_subscription_type.stripe_product_id,
|
||||
canonical_subscription_type.stripe_price_id,
|
||||
canonical_subscription_type.active,
|
||||
)
|
||||
existing_canonical_subscription_types[id] = resource
|
||||
else:
|
||||
canonical_subscription_type = CANONICAL_SUBSCRIPTION_TYPES[id]
|
||||
resource = update_subscription_type(
|
||||
id,
|
||||
canonical_subscription_type.name,
|
||||
canonical_subscription_type.description,
|
||||
canonical_subscription_type.choices,
|
||||
canonical_subscription_type.icon_url,
|
||||
canonical_subscription_type.stripe_product_id,
|
||||
canonical_subscription_type.stripe_price_id,
|
||||
canonical_subscription_type.active,
|
||||
|
|
|
@ -12,6 +12,7 @@ class SubscriptionTypeResourceData(BaseModel):
|
|||
id: str
|
||||
name: str
|
||||
description: str
|
||||
choices: List[str] = Field(default_factory=list)
|
||||
icon_url: str
|
||||
stripe_product_id: Optional[str] = None
|
||||
stripe_price_id: Optional[str] = None
|
||||
|
|
|
@ -296,9 +296,9 @@ class EthereumTXPoolProvider(BugoutEventProvider):
|
|||
for subscription in relevant_subscriptions
|
||||
]
|
||||
subscriptions_filters = []
|
||||
for adress in addresses:
|
||||
for address in addresses:
|
||||
subscriptions_filters.extend(
|
||||
[f"?#from_address:{adress}", f"?#to_address:{adress}"]
|
||||
[f"?#from_address:{address}", f"?#to_address:{address}"]
|
||||
)
|
||||
|
||||
return subscriptions_filters
|
||||
|
|
|
@ -174,7 +174,8 @@ def query_ethereum_transactions(
|
|||
EthereumTransaction.value,
|
||||
EthereumBlock.timestamp.label("timestamp"),
|
||||
).join(
|
||||
EthereumBlock, EthereumTransaction.block_number == EthereumBlock.block_number
|
||||
EthereumBlock,
|
||||
EthereumTransaction.block_number == EthereumBlock.block_number,
|
||||
)
|
||||
|
||||
if stream_boundary.include_start:
|
||||
|
|
|
@ -12,10 +12,13 @@ import {
|
|||
Button,
|
||||
Modal,
|
||||
useDisclosure,
|
||||
ModalHeader,
|
||||
ModalCloseButton,
|
||||
ModalBody,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
} from "@chakra-ui/react";
|
||||
import NewSubscription from "../src/components/NewModalSubscripton";
|
||||
import NewSubscription from "../src/components/NewSubscription";
|
||||
import { AiOutlinePlusCircle } from "react-icons/ai";
|
||||
|
||||
const Subscriptions = () => {
|
||||
|
@ -52,10 +55,15 @@ const Subscriptions = () => {
|
|||
<ModalOverlay />
|
||||
|
||||
<ModalContent>
|
||||
<NewSubscription
|
||||
isFreeOption={isAddingFreeSubscription}
|
||||
onClose={onClose}
|
||||
/>
|
||||
<ModalHeader>Subscribe to a new address</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<NewSubscription
|
||||
isFreeOption={isAddingFreeSubscription}
|
||||
onClose={onClose}
|
||||
isModal={true}
|
||||
/>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
{subscriptionsCache.isLoading ? (
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
AccordionButton,
|
||||
AccordionPanel,
|
||||
AccordionIcon,
|
||||
Divider,
|
||||
} from "@chakra-ui/react";
|
||||
import StepProgress from "../src/components/StepProgress";
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "@chakra-ui/icons";
|
||||
|
@ -95,7 +96,7 @@ const Welcome = () => {
|
|||
<Fade in>
|
||||
<Stack spacing={4}>
|
||||
<Stack
|
||||
px={12}
|
||||
px={[0, 12, null]}
|
||||
// mt={24}
|
||||
bgColor="gray.50"
|
||||
borderRadius="xl"
|
||||
|
@ -119,7 +120,7 @@ const Welcome = () => {
|
|||
</Text>
|
||||
</Stack>
|
||||
<Stack
|
||||
px={12}
|
||||
px={[0, 12, null]}
|
||||
// mt={24}
|
||||
bgColor="gray.50"
|
||||
borderRadius="xl"
|
||||
|
@ -176,7 +177,7 @@ const Welcome = () => {
|
|||
</Accordion>
|
||||
</Stack>
|
||||
<Stack
|
||||
px={12}
|
||||
px={[0, 12, null]}
|
||||
// mt={24}
|
||||
bgColor="gray.50"
|
||||
borderRadius="xl"
|
||||
|
@ -298,7 +299,7 @@ const Welcome = () => {
|
|||
<Fade in>
|
||||
<Stack px="7%">
|
||||
<Stack
|
||||
px={12}
|
||||
px={[0, 12, null]}
|
||||
// mt={24}
|
||||
bgColor="gray.50"
|
||||
borderRadius="xl"
|
||||
|
@ -345,14 +346,18 @@ const Welcome = () => {
|
|||
)}
|
||||
<SubscriptionsList />
|
||||
{showSubscriptionForm && (
|
||||
<>
|
||||
<Heading pt={12}>{`Let's add new subscription!`}</Heading>
|
||||
<Flex direction="column" pt={6}>
|
||||
<Divider bgColor="gray.500" borderWidth="2px" />
|
||||
<Heading
|
||||
size="md"
|
||||
pt={2}
|
||||
>{`Let's add new subscription!`}</Heading>
|
||||
|
||||
<NewSubscription
|
||||
isFreeOption={false}
|
||||
onClose={SubscriptonCreatedCallback}
|
||||
/>
|
||||
</>
|
||||
</Flex>
|
||||
)}
|
||||
{!showSubscriptionForm && (
|
||||
<Button
|
||||
|
@ -370,7 +375,7 @@ const Welcome = () => {
|
|||
<Fade in>
|
||||
<Stack>
|
||||
<Stack
|
||||
px={12}
|
||||
px={[0, 12, null]}
|
||||
// mt={24}
|
||||
bgColor="gray.50"
|
||||
borderRadius="xl"
|
||||
|
|
|
@ -18,6 +18,24 @@ const baseStyle = (props) => {
|
|||
};
|
||||
};
|
||||
|
||||
const variantSuggestion = (props) => {
|
||||
const bg = mode("primary.700", "primary.300")(props);
|
||||
return {
|
||||
"--tooltip-bg": `colors.${bg}`,
|
||||
px: "8px",
|
||||
py: "2px",
|
||||
bg: "var(--tooltip-bg)",
|
||||
"--popper-arrow-bg": "var(--tooltip-bg)",
|
||||
color: mode("whiteAlpha.900", "gray.900")(props),
|
||||
borderRadius: "md",
|
||||
fontWeight: "medium",
|
||||
fontSize: "sm",
|
||||
boxShadow: "md",
|
||||
maxW: "320px",
|
||||
zIndex: "tooltip",
|
||||
};
|
||||
};
|
||||
|
||||
const variantOnboarding = (props) => {
|
||||
const bg = mode("secondary.700", "secondary.300")(props);
|
||||
return {
|
||||
|
@ -38,6 +56,7 @@ const variantOnboarding = (props) => {
|
|||
|
||||
const variants = {
|
||||
onboarding: variantOnboarding,
|
||||
suggestion: variantSuggestion,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { useSubscriptions } from "../core/hooks";
|
||||
import {
|
||||
Input,
|
||||
Stack,
|
||||
Text,
|
||||
HStack,
|
||||
useRadioGroup,
|
||||
FormControl,
|
||||
FormErrorMessage,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalHeader,
|
||||
Button,
|
||||
ModalFooter,
|
||||
Spinner,
|
||||
IconButton,
|
||||
} from "@chakra-ui/react";
|
||||
import RadioCard from "./RadioCard";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { GithubPicker } from "react-color";
|
||||
import { BiRefresh } from "react-icons/bi";
|
||||
import { makeColor } from "../core/utils/makeColor";
|
||||
const NewSubscription = ({
|
||||
isFreeOption,
|
||||
onClose,
|
||||
initialAddress,
|
||||
initialType,
|
||||
}) => {
|
||||
const [color, setColor] = useState(makeColor());
|
||||
const { typesCache, createSubscription } = useSubscriptions();
|
||||
const { handleSubmit, errors, register } = useForm({});
|
||||
const [radioState, setRadioState] = useState(
|
||||
initialType ?? "ethereum_blockchain"
|
||||
);
|
||||
let { getRootProps, getRadioProps } = useRadioGroup({
|
||||
name: "type",
|
||||
defaultValue: radioState,
|
||||
onChange: setRadioState,
|
||||
});
|
||||
|
||||
const group = getRootProps();
|
||||
|
||||
useEffect(() => {
|
||||
if (createSubscription.isSuccess) {
|
||||
onClose();
|
||||
}
|
||||
}, [createSubscription.isSuccess, onClose]);
|
||||
|
||||
if (typesCache.isLoading) return <Spinner />;
|
||||
|
||||
const createSubscriptionWrap = (props) => {
|
||||
createSubscription.mutate({
|
||||
...props,
|
||||
color: color,
|
||||
type: isFreeOption ? "free" : radioState,
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangeColorComplete = (color) => {
|
||||
setColor(color.hex);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(createSubscriptionWrap)}>
|
||||
<ModalHeader>Subscribe to a new address</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<FormControl isInvalid={errors.label}>
|
||||
<Input
|
||||
my={2}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
placeholder="Enter label"
|
||||
name="label"
|
||||
ref={register({ required: "label is required!" })}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors.label && errors.label.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={errors.address}>
|
||||
<Input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
my={2}
|
||||
placeholder="Enter address"
|
||||
defaultValue={initialAddress ?? undefined}
|
||||
isReadOnly={!!initialAddress}
|
||||
name="address"
|
||||
ref={register({ required: "address is required!" })}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors.address && errors.address.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<Stack my={16} direction="column">
|
||||
<Text fontWeight="600">
|
||||
{isFreeOption
|
||||
? `Free subscription is only availible Ethereum blockchain source`
|
||||
: `On which source?`}
|
||||
</Text>
|
||||
|
||||
<FormControl isInvalid={errors.subscription_type}>
|
||||
<HStack {...group} alignItems="stretch">
|
||||
{typesCache.data.map((type) => {
|
||||
const radio = getRadioProps({
|
||||
value: type.id,
|
||||
isDisabled:
|
||||
(initialAddress && initialType) ||
|
||||
!type.active ||
|
||||
(isFreeOption && type.id !== "ethereum_blockchain"),
|
||||
});
|
||||
return (
|
||||
<RadioCard key={`subscription_type_${type.id}`} {...radio}>
|
||||
{type.name}
|
||||
</RadioCard>
|
||||
);
|
||||
})}
|
||||
</HStack>
|
||||
<Input
|
||||
type="hidden"
|
||||
placeholder="subscription_type"
|
||||
name="subscription_type"
|
||||
ref={register({ required: "select type" })}
|
||||
value={radioState}
|
||||
onChange={() => null}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors.subscription_type && errors.subscription_type.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<FormControl isInvalid={errors.color}>
|
||||
<Stack direction="row" pb={2}>
|
||||
<Text fontWeight="600" alignSelf="center">
|
||||
Label color
|
||||
</Text>{" "}
|
||||
<IconButton
|
||||
size="md"
|
||||
color={"white.100"}
|
||||
_hover={{ bgColor: { color } }}
|
||||
bgColor={color}
|
||||
variant="outline"
|
||||
onClick={() => setColor(makeColor())}
|
||||
icon={<BiRefresh />}
|
||||
/>
|
||||
<Input
|
||||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
ref={register({ required: "color is required!" })}
|
||||
value={color}
|
||||
onChange={() => null}
|
||||
w="200px"
|
||||
></Input>
|
||||
</Stack>
|
||||
|
||||
<GithubPicker onChangeComplete={handleChangeColorComplete} />
|
||||
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors.color && errors.color.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
colorScheme="suggested"
|
||||
isLoading={createSubscription.isLoading}
|
||||
>
|
||||
Confirm
|
||||
</Button>
|
||||
<Button colorScheme="gray" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewSubscription;
|
|
@ -12,13 +12,13 @@ import {
|
|||
Spinner,
|
||||
IconButton,
|
||||
ButtonGroup,
|
||||
Spacer,
|
||||
Flex,
|
||||
} from "@chakra-ui/react";
|
||||
import RadioCard from "./RadioCard";
|
||||
// import { useForm } from "react-hook-form";
|
||||
import { CirclePicker } from "react-color";
|
||||
import { BiRefresh } from "react-icons/bi";
|
||||
import { GithubPicker } from "react-color";
|
||||
import { makeColor } from "../core/utils/makeColor";
|
||||
import { useForm } from "react-hook-form";
|
||||
const _NewSubscription = ({
|
||||
|
@ -27,21 +27,35 @@ const _NewSubscription = ({
|
|||
setIsLoading,
|
||||
initialAddress,
|
||||
initialType,
|
||||
isModal,
|
||||
}) => {
|
||||
const [color, setColor] = useState(makeColor());
|
||||
const { handleSubmit, errors, register } = useForm({});
|
||||
const { typesCache, createSubscription } = useSubscriptions();
|
||||
// const { handleSubmit, errors, register } = useForm({});
|
||||
|
||||
const [radioState, setRadioState] = useState(
|
||||
initialType ?? "ethereum_blockchain"
|
||||
);
|
||||
let { getRootProps, getRadioProps } = useRadioGroup({
|
||||
|
||||
const mapper = {
|
||||
"tag:erc721": "NFTs",
|
||||
"input:address": "Address",
|
||||
};
|
||||
|
||||
const [subscriptionAdressFormatRadio, setsubscriptionAdressFormatRadio] =
|
||||
useState("input:address");
|
||||
|
||||
let { getRadioProps } = useRadioGroup({
|
||||
name: "type",
|
||||
defaultValue: radioState,
|
||||
onChange: setRadioState,
|
||||
});
|
||||
|
||||
const group = getRootProps();
|
||||
let { getRadioProps: getRadioPropsSubscription } = useRadioGroup({
|
||||
name: "subscription",
|
||||
defaultValue: subscriptionAdressFormatRadio,
|
||||
onChange: setsubscriptionAdressFormatRadio,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (setIsLoading) {
|
||||
|
@ -57,17 +71,40 @@ const _NewSubscription = ({
|
|||
|
||||
const createSubscriptionWrapper = useCallback(
|
||||
(props) => {
|
||||
props.label = "Address";
|
||||
if (
|
||||
subscriptionAdressFormatRadio.startsWith("tag") &&
|
||||
radioState != "ethereum_whalewatch"
|
||||
) {
|
||||
props.address = subscriptionAdressFormatRadio;
|
||||
props.label = "Tag";
|
||||
}
|
||||
|
||||
createSubscription.mutate({
|
||||
...props,
|
||||
color: color,
|
||||
type: isFreeOption ? "ethereum_blockchain" : radioState,
|
||||
});
|
||||
},
|
||||
[createSubscription, isFreeOption, color, radioState]
|
||||
[
|
||||
createSubscription,
|
||||
isFreeOption,
|
||||
color,
|
||||
radioState,
|
||||
subscriptionAdressFormatRadio,
|
||||
]
|
||||
);
|
||||
|
||||
if (typesCache.isLoading) return <Spinner />;
|
||||
|
||||
function search(nameKey, myArray) {
|
||||
for (var i = 0; i < myArray.length; i++) {
|
||||
if (myArray[i].id === nameKey) {
|
||||
return myArray[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleChangeColorComplete = (color) => {
|
||||
setColor(color.hex);
|
||||
};
|
||||
|
@ -76,110 +113,177 @@ const _NewSubscription = ({
|
|||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(createSubscriptionWrapper)}>
|
||||
<FormControl isInvalid={errors?.label}>
|
||||
<Input
|
||||
my={2}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
placeholder="Name of subscription (you can change it later)"
|
||||
name="label"
|
||||
ref={register({ required: "label is required!" })}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors?.label && errors?.label.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={errors?.address}>
|
||||
<Input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
my={2}
|
||||
placeholder="Address to subscribe to"
|
||||
name="address"
|
||||
ref={register({ required: "address is required!" })}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors?.address && errors?.address.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<Stack my={4} direction="column">
|
||||
{/* <Text fontWeight="600">
|
||||
{isFreeOption
|
||||
? `Right now you can subscribe only to ethereum blockchain`
|
||||
: `On which source?`}
|
||||
</Text> */}
|
||||
<Stack spacing={1} w="100%">
|
||||
<Text fontWeight="600">Source:</Text>
|
||||
{/* position must be relative otherwise radio boxes add strange spacing on selection */}
|
||||
<Stack
|
||||
spacing={1}
|
||||
w="100%"
|
||||
direction="row"
|
||||
flexWrap="wrap"
|
||||
position="relative"
|
||||
>
|
||||
{typesCache.data
|
||||
.sort((a, b) =>
|
||||
a?.name > b?.name ? 1 : b?.name > a?.name ? -1 : 0
|
||||
)
|
||||
.map((type) => {
|
||||
const radio = getRadioProps({
|
||||
value: type.id,
|
||||
isDisabled:
|
||||
(initialAddress && initialType) ||
|
||||
!type.active ||
|
||||
(isFreeOption && type.id !== "ethereum_blockchain"),
|
||||
});
|
||||
|
||||
<FormControl isInvalid={errors?.subscription_type}>
|
||||
<HStack {...group} alignItems="stretch">
|
||||
{typesCache.data.map((type) => {
|
||||
const radio = getRadioProps({
|
||||
value: type.id,
|
||||
isDisabled:
|
||||
(initialAddress && initialType) ||
|
||||
!type.active ||
|
||||
(isFreeOption && type.id !== "ethereum_blockchain"),
|
||||
});
|
||||
return (
|
||||
<RadioCard key={`subscription_type_${type.id}`} {...radio}>
|
||||
{type.name}
|
||||
</RadioCard>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<RadioCard
|
||||
px="8px"
|
||||
py="4px"
|
||||
mt="2px"
|
||||
w="190px"
|
||||
{...radio}
|
||||
key={`subscription_type_${type.id}`}
|
||||
label={type.description}
|
||||
iconURL={type.icon_url}
|
||||
>
|
||||
{type.name.slice(9, type.name.length)}
|
||||
</RadioCard>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Flex direction="row" w="100%" flexWrap="wrap" pt={4}>
|
||||
{/* position must be relative otherwise radio boxes add strange spacing on selection */}
|
||||
<HStack flexGrow={0} flexBasis="140px" position="relative">
|
||||
{search(radioState, typesCache.data).choices.length > 0 && (
|
||||
<Text fontWeight="600">Type:</Text>
|
||||
)}
|
||||
{search(radioState, typesCache.data).choices.map(
|
||||
(addition_selects) => {
|
||||
const radio = getRadioPropsSubscription({
|
||||
value: addition_selects,
|
||||
isDisabled: addition_selects.startsWith("tag"),
|
||||
});
|
||||
return (
|
||||
<RadioCard
|
||||
px="4px"
|
||||
py="2px"
|
||||
key={`subscription_tags_${addition_selects}`}
|
||||
{...radio}
|
||||
>
|
||||
{mapper[addition_selects]}
|
||||
</RadioCard>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</HStack>
|
||||
<Input
|
||||
type="hidden"
|
||||
placeholder="subscription_type"
|
||||
name="subscription_type"
|
||||
ref={register({ required: "select type" })}
|
||||
value={radioState}
|
||||
onChange={() => null}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors?.subscription_type && errors?.subscription_type.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
{subscriptionAdressFormatRadio.startsWith("input") &&
|
||||
radioState != "ethereum_whalewatch" && (
|
||||
<Flex flexBasis="240px" flexGrow={1}>
|
||||
<FormControl isInvalid={errors?.address}>
|
||||
<Input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
my={2}
|
||||
placeholder="Address to subscribe to"
|
||||
name="address"
|
||||
ref={register({ required: "address is required!" })}
|
||||
></Input>
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors?.address && errors?.address.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
<Input
|
||||
type="hidden"
|
||||
placeholder="subscription_type"
|
||||
name="subscription_type"
|
||||
ref={register({ required: "select type" })}
|
||||
value={radioState}
|
||||
onChange={() => null}
|
||||
></Input>
|
||||
</Stack>
|
||||
<FormControl isInvalid={errors?.color}>
|
||||
<Flex direction="row" pb={2} flexWrap="wrap">
|
||||
<Stack pt={2} direction="row" h="min-content">
|
||||
{!isModal ? (
|
||||
<Flex direction="row" pb={2} flexWrap="wrap" alignItems="baseline">
|
||||
<Text fontWeight="600" alignSelf="center">
|
||||
Label color
|
||||
</Text>{" "}
|
||||
<IconButton
|
||||
size="md"
|
||||
// colorScheme="primary"
|
||||
color={"white.100"}
|
||||
_hover={{ bgColor: { color } }}
|
||||
bgColor={color}
|
||||
variant="outline"
|
||||
onClick={() => setColor(makeColor())}
|
||||
icon={<BiRefresh />}
|
||||
/>
|
||||
<Input
|
||||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
ref={register({ required: "color is required!" })}
|
||||
value={color}
|
||||
onChange={() => null}
|
||||
w="200px"
|
||||
></Input>
|
||||
</Stack>
|
||||
<Flex p={2}>
|
||||
<CirclePicker
|
||||
onChangeComplete={handleChangeColorComplete}
|
||||
circleSpacing={1}
|
||||
circleSize={24}
|
||||
/>
|
||||
<Stack
|
||||
// pt={2}
|
||||
direction={["row", "row", null]}
|
||||
h="min-content"
|
||||
alignSelf="center"
|
||||
>
|
||||
<IconButton
|
||||
size="md"
|
||||
// colorScheme="primary"
|
||||
color={"white.100"}
|
||||
_hover={{ bgColor: { color } }}
|
||||
bgColor={color}
|
||||
variant="outline"
|
||||
onClick={() => setColor(makeColor())}
|
||||
icon={<BiRefresh />}
|
||||
/>
|
||||
<Input
|
||||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
ref={register({ required: "color is required!" })}
|
||||
value={color}
|
||||
onChange={() => null}
|
||||
w="200px"
|
||||
></Input>
|
||||
</Stack>
|
||||
<Flex p={2} flexBasis="120px" flexGrow={1} alignSelf="center">
|
||||
<CirclePicker
|
||||
width="100%"
|
||||
onChangeComplete={handleChangeColorComplete}
|
||||
circleSpacing={1}
|
||||
circleSize={24}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
) : (
|
||||
<>
|
||||
<Stack direction="row" pb={2}>
|
||||
<Text fontWeight="600" alignSelf="center">
|
||||
Label color
|
||||
</Text>{" "}
|
||||
<IconButton
|
||||
size="md"
|
||||
color={"white.100"}
|
||||
_hover={{ bgColor: { color } }}
|
||||
bgColor={color}
|
||||
variant="outline"
|
||||
onClick={() => setColor(makeColor())}
|
||||
icon={<BiRefresh />}
|
||||
/>
|
||||
<Input
|
||||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
ref={register({ required: "color is required!" })}
|
||||
value={color}
|
||||
onChange={() => null}
|
||||
w="200px"
|
||||
></Input>
|
||||
</Stack>
|
||||
|
||||
<GithubPicker onChangeComplete={handleChangeColorComplete} />
|
||||
</>
|
||||
)}
|
||||
<FormErrorMessage color="unsafe.400" pl="1">
|
||||
{errors?.color && errors?.color.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
|
||||
<ButtonGroup direction="row" justifyContent="space-evenly">
|
||||
<ButtonGroup direction="row" justifyContent="flex-end" w="100%">
|
||||
<Button
|
||||
type="submit"
|
||||
colorScheme="suggested"
|
||||
|
@ -187,7 +291,7 @@ const _NewSubscription = ({
|
|||
>
|
||||
Confirm
|
||||
</Button>
|
||||
<Spacer />
|
||||
|
||||
<Button colorScheme="gray" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { useRadio, Box, Flex } from "@chakra-ui/react";
|
||||
import { useRadio, Box, Flex, Tooltip, Image } from "@chakra-ui/react";
|
||||
|
||||
const RadioCard = (props) => {
|
||||
const { getInputProps, getCheckboxProps } = useRadio(props);
|
||||
|
@ -8,38 +8,48 @@ const RadioCard = (props) => {
|
|||
const checkbox = getCheckboxProps();
|
||||
|
||||
return (
|
||||
<Flex as="label" h="fill-availible">
|
||||
<input {...input} />
|
||||
<Box
|
||||
justifyContent="left"
|
||||
alignContent="center"
|
||||
{...checkbox}
|
||||
cursor="pointer"
|
||||
borderWidth="1px"
|
||||
borderRadius="md"
|
||||
boxShadow="md"
|
||||
_disabled={{
|
||||
bg: "gray.300",
|
||||
color: "gray.900",
|
||||
borderColor: "gray.300",
|
||||
}}
|
||||
_checked={{
|
||||
bg: "secondary.900",
|
||||
color: "white",
|
||||
borderColor: "secondary.900",
|
||||
}}
|
||||
_focus={{
|
||||
boxShadow: "outline",
|
||||
}}
|
||||
px={5}
|
||||
py={3}
|
||||
fontWeight="600"
|
||||
>
|
||||
{props.children}
|
||||
</Box>
|
||||
</Flex>
|
||||
<Tooltip
|
||||
hidden={props.label ? false : true}
|
||||
label={props.label}
|
||||
variant="suggestion"
|
||||
openDelay={500}
|
||||
>
|
||||
<Flex as="label" h="fill-availible">
|
||||
<input {...input} />
|
||||
<Box
|
||||
alignContent="center"
|
||||
{...checkbox}
|
||||
cursor="pointer"
|
||||
borderWidth="1px"
|
||||
borderRadius="lg"
|
||||
boxShadow="md"
|
||||
_disabled={{
|
||||
bg: "gray.300",
|
||||
color: "gray.900",
|
||||
borderColor: "gray.300",
|
||||
}}
|
||||
_checked={{
|
||||
// bg: "secondary.900",
|
||||
|
||||
color: "secondary.900",
|
||||
borderColor: "secondary.900",
|
||||
borderWidth: "4px",
|
||||
}}
|
||||
justifyContent="center"
|
||||
px={props.px}
|
||||
mt={props.mt}
|
||||
py={props.py}
|
||||
w={props.w}
|
||||
fontWeight="600"
|
||||
>
|
||||
{props.iconURL && (
|
||||
<Image display="inline-block" w="16px" src={props.iconURL} />
|
||||
)}{" "}
|
||||
{props.children}
|
||||
</Box>
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
// const RadioCard = chakra(RadioCard_);
|
||||
export default RadioCard;
|
||||
|
|
|
@ -21,6 +21,11 @@ import { useSubscriptions } from "../core/hooks";
|
|||
import ConfirmationRequest from "./ConfirmationRequest";
|
||||
import ColorSelector from "./ColorSelector";
|
||||
|
||||
const mapper = {
|
||||
"tag:erc721": "NFTs",
|
||||
"input:address": "Address",
|
||||
};
|
||||
|
||||
const SubscriptionsList = ({ emptyCTA }) => {
|
||||
const {
|
||||
subscriptionsCache,
|
||||
|
@ -94,7 +99,11 @@ const SubscriptionsList = ({ emptyCTA }) => {
|
|||
</Editable>
|
||||
</Td>
|
||||
<Td mr={4} p={0}>
|
||||
<CopyButton>{subscription.address}</CopyButton>
|
||||
{subscription.address?.startsWith("tag") ? (
|
||||
<CopyButton>{mapper[subscription.address]}</CopyButton>
|
||||
) : (
|
||||
<CopyButton>{subscription.address}</CopyButton>
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
<ColorSelector
|
||||
|
|
|
@ -21,7 +21,7 @@ import { useToast } from "../../core/hooks";
|
|||
import { useSubscriptions } from "../../core/hooks";
|
||||
import moment from "moment";
|
||||
import { AiOutlineMonitor } from "react-icons/ai";
|
||||
import NewSubscription from "../NewModalSubscripton";
|
||||
import NewSubscription from "../NewSubscription";
|
||||
|
||||
const EthereumWhalewatchCard_ = ({
|
||||
entry,
|
||||
|
|
Ładowanie…
Reference in New Issue