react-bootstrap#Modal TypeScript Examples

The following examples show how to use react-bootstrap#Modal. 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: queue.tsx    From remote-office-hours-queue with Apache License 2.0 6 votes vote down vote up
ChangeMeetingTypeDialog = (props: ChangeMeetingTypeDialogProps) => {
    const handleSubmit = () => {
        props.onClose();
        props.onSubmit(props.queue.my_meeting?.backend_type as string);
    }
    return (
        <Modal show={props.show} onHide={props.onClose}>
            <Modal.Header closeButton>
                <Modal.Title>Change Meeting Type</Modal.Title>
            </Modal.Header>
            <Modal.Body>
                <div className="row col-lg">
                    <p>Select Meeting Type</p>
                    <p className="required">*</p>
                </div>
                <BackendSelector backends={props.backends}
                    allowedBackends={new Set(props.queue.allowed_backends)}
                    onChange={props.onChangeBackend}
                    selectedBackend={props.selectedBackend}/>
            </Modal.Body>
            <Modal.Footer>
                <Button variant="secondary" onClick={props.onClose}>Cancel</Button>
                <Button variant="primary" onClick={handleSubmit}>OK</Button>
            </Modal.Footer>
        </Modal>
    );
}
Example #2
Source File: common.tsx    From remote-office-hours-queue with Apache License 2.0 6 votes vote down vote up
LoginDialog = (props: LoginDialogProps) =>
    <Modal show={props.visible}>
        <Modal.Header>
            <Modal.Title>Session Expired</Modal.Title>
        </Modal.Header>
        <Modal.Body>
            <p className="alert alert-warning">Your session has timed out. Some work may be lost. Please login again via the "Login" link below.</p>
        </Modal.Body>
        <Modal.Footer>
            <a href={props.loginUrl + '?next=' + location.pathname} className="btn btn-primary">Login</a>
        </Modal.Footer>
    </Modal>
Example #3
Source File: RawDataViewer.tsx    From apps with MIT License 6 votes vote down vote up
render() {
        const block = this.props.block ?? true;
        return (
            <>
                <Button
                    variant="outline-info"
                    block={block}
                    onClick={() => {
                        this.show();
                    }}
                >
                    {this.props.text || "View"}
                    &nbsp;
                    <FontAwesomeIcon icon={faSearchPlus} />
                </Button>

                <Modal size={"lg"} show={this.state.showing} onHide={() => this.hide()}>
                    <Modal.Header closeButton>
                        <Modal.Title>Raw Data Viewer</Modal.Title>
                    </Modal.Header>
                    <Modal.Body lang="en-US">
                        {this.state.data ? (
                            <ReactJson
                                style={{ wordBreak: "break-all" }}
                                src={this.state.data}
                                collapsed={1}
                                theme={viewerTheme.get(Manager.theme()) ?? "rjv-default"}
                                enableClipboard={(clipboard) => {
                                    if (typeof clipboard.src === "string") {
                                        copy(clipboard.src);
                                    }
                                }}
                            />
                        ) : null}
                    </Modal.Body>
                </Modal>
            </>
        );
    }
Example #4
Source File: EnemyActorConfigModal.tsx    From apps with MIT License 6 votes vote down vote up
render() {
        return (
            <Modal show={this.props.open} size="xl" onHide={this.props.close}>
                <Modal.Header closeButton>
                    <Modal.Title>Enemy Configuration</Modal.Title>
                </Modal.Header>

                <Modal.Body>
                    <Form>
                        <Form.Group>
                            <Form.Label>Name</Form.Label>
                            <Form.Control
                                type="text"
                                disabled={this.props.loading}
                                value={this.props.servantOptions?.name}
                            />
                        </Form.Group>
                    </Form>
                </Modal.Body>

                <Modal.Footer>
                    <Button variant="secondary" onClick={this.props.close}>
                        Close
                    </Button>
                    <Button variant="primary" onClick={this.props.add}>
                        Add
                    </Button>
                </Modal.Footer>
            </Modal>
        );
    }
Example #5
Source File: index.tsx    From nouns-monorepo with GNU General Public License v3.0 6 votes vote down vote up
NetworkAlert = () => {
  return (
    <>
      <Modal show={true} backdrop="static" keyboard={false}>
        <Modal.Header>
          <Modal.Title>Wrong Network Detected</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <p>
            Nouns DAO auctions require you to switch over {networkName()} to be able to participate.
          </p>
          <p>
            <b>To get started, please switch your network by following the instructions below:</b>
          </p>
          <ol>
            <li>Open Metamask</li>
            <li>Click the network select dropdown</li>
            <li>Click on "{metamaskNetworkName()}"</li>
          </ol>
        </Modal.Body>
      </Modal>
    </>
  );
}
Example #6
Source File: CustomModal.tsx    From cftracker with MIT License 6 votes vote down vote up
CustomModal = (props: PropsType) => {
  const [show, setShow] = useState(false);

  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

  return (
    <>
      <button
        type="button"
        className={"btn " + props.theme.btn}
        onClick={handleShow}>
        {<FontAwesomeIcon icon={faFilter} />}
      </button>
      <Modal className="modal" show={show} onHide={handleClose}>
        <Modal.Header className={"modal-header " + props.theme.bgText}>
          <Modal.Title>{props.title}</Modal.Title>
          <button
            type="button"
            className="btn-close"
            data-bs-dismiss="modal"
            aria-label="Close"
            onClick={() => handleClose()}></button>
        </Modal.Header>
        <Modal.Body className={props.theme.bgText}>{props.children}</Modal.Body>
      </Modal>
    </>
  );
}
Example #7
Source File: message-modal.tsx    From polkabtc-ui with Apache License 2.0 6 votes vote down vote up
export default function MessageModal(props: MessageModalProps): ReactElement {
  const { t } = useTranslation();

  return (
    <Modal
      show={props.show}
      onHide={props.onClose}
      size='lg'>
      <Modal.Header closeButton>
        <Modal.Title>{t('message')}</Modal.Title>
      </Modal.Header>
      <Modal.Body>
        {props.statusUpdate && (
          <React.Fragment>
            <div className='row'>
              <div className='col-xl-9 col-lg-8 col-md-6'>
                {props.statusUpdate.message === '' ? '-' : props.statusUpdate.message}
              </div>
            </div>
          </React.Fragment>
        )}
      </Modal.Body>
      <Modal.Footer>
        <Button
          variant='secondary'
          onClick={props.onClose}>
          {t('cancel')}
        </Button>
      </Modal.Footer>
    </Modal>
  );
}
Example #8
Source File: notification-page.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 6 votes vote down vote up
NotificationPage = (props: any) => {

    const { t } = useTranslation();
    const [show, setShow] = React.useState(true);

    React.useEffect(() => {
        if (props)
            setShow(props.show);
    }, [props, props.show])

    return (
        <>
            <Modal
                dialogClassName='align-items-end'
                contentClassName='border-0 bg-transparent'
                show={show}
                backdrop={false}
                keyboard={false}
                centered
                onEnter={() => setTimeout(props.setNotificationShow, 3000, false)}

            >
                <Alert className='qt-notification' variant='success' onClose={() => props.setNotificationShow(false)}>
                    <Image src={successIcon} className='mr-3 my-3' />
                    <p className='qt-notification-text my-auto mx-1'>
                        {t('translation:successfull-transferred')}
                    </p>
                </Alert>
            </Modal>
        </>
    )
}
Example #9
Source File: LabelModal.tsx    From devex with GNU General Public License v3.0 5 votes vote down vote up
LabelModal: React.FC<IProps> = ({ show, handleCloseModal, addLabel }) => {
  const themeContext = useContext(ThemeContext);
  const { theme } = themeContext!;
  const [labelInput, setLabelInput] = useState("");

  const handleSubmit = (e: React.SyntheticEvent) => {
    e.preventDefault();
    setLabelInput("");
    addLabel(labelInput);
  };

  return (
    <Modal
      className={
        theme === "dark"
          ? "custom-modal dark-theme"
          : "custom-modal light-theme"
      }
      show={show}
      onHide={handleCloseModal}
    >
      <div className="modal-header">
        <h6>Add Label</h6>
      </div>
      <Modal.Body>
        <Form onSubmit={handleSubmit}>
          <div className="mb-3">
            <Form.Control
              autoFocus={true}
              required
              type="text"
              value={labelInput}
              maxLength={20}
              onChange={(e) => {
                setLabelInput(sanitizeHtml(e.target.value));
              }}
              placeholder="Label Name"
            />
          </div>
          <div>
            <Button block type="submit">
              Save
            </Button>
          </div>
        </Form>
        <div className="modal-footer">
          <span>Labels can be accessed from the Labels Page</span>
          <br />
          <span>Label data is saved in the local storage of your browser</span>
        </div>
      </Modal.Body>
    </Modal>
  );
}
Example #10
Source File: queueManager.tsx    From remote-office-hours-queue with Apache License 2.0 5 votes vote down vote up
MeetingInfoDialog = (props: MeetingInfoDialogProps) => {
    const attendeeDetails = props.meeting?.attendees.map((a, key) => <p key={key}><UserDisplay user={a}/></p>);
    const generalInfo = props.meeting
        && (
            <>
            Attendees:
            <div>{attendeeDetails}</div>
            <p>
                Time Joined: <DateTimeDisplay dateTime={props.meeting.created_at}/>
            </p>
            <p>
                Agenda: {props.meeting.agenda}
            </p>
            </>
        );

    const meetingType = props.meeting?.backend_type;
    let metadataInfo;
    if (props.meeting && meetingType && props.meeting.backend_metadata) {
        const meetingBackend = getBackendByName(meetingType, props.backends);
        metadataInfo = VideoBackendNames.includes(meetingType)
            ? (
                <>
                <p>This meeting will be via <strong>{meetingBackend.friendly_name}</strong>.</p>
                <DialInContent metadata={props.meeting.backend_metadata} backend={meetingBackend} isHost />
                </>
            )
            : <div><p>This meeting will be <strong>In Person</strong>.</p></div>;
    }

    return (
        <Modal show={!!props.meeting} onHide={props.onClose}>
            <Modal.Header closeButton>
                <Modal.Title data-id={props.meeting?.id}>Join Info</Modal.Title>
            </Modal.Header>
            <Modal.Body>
                {generalInfo}
                {metadataInfo}
            </Modal.Body>
            <Modal.Footer>
                <Button variant="primary" onClick={props.onClose}>Close</Button>
            </Modal.Footer>
        </Modal>
    );
}
Example #11
Source File: UploadTypeChoiceModal.tsx    From bada-frame with GNU General Public License v3.0 5 votes vote down vote up
export default function UploadTypeChoiceModal({
    onHide,
    show,
    uploadFiles,
    uploadFolders,
    uploadGoogleTakeoutZips,
}) {
    return (
        <Modal
            show={show}
            aria-labelledby="contained-modal-title-vcenter"
            centered
            dialogClassName="file-type-choice-modal">
            <Modal.Header
                onHide={onHide}
                style={{
                    borderBottom: 'none',
                    height: '4em',
                }}>
                <Modal.Title
                    id="contained-modal-title-vcenter"
                    style={{
                        fontSize: '1.8em',
                        marginLeft: '5%',
                        color: 'white',
                    }}>
                    <b>{constants.CHOOSE_UPLOAD_TYPE}</b>
                </Modal.Title>
                <IoMdClose
                    size={30}
                    onClick={onHide}
                    style={{ cursor: 'pointer' }}
                />
            </Modal.Header>
            <Modal.Body>
                <Container>
                    <UploadTypeRow
                        uploadFunc={uploadFiles}
                        Icon={FileUploadIcon}
                        uploadName={constants.UPLOAD_FILES}
                    />
                    <UploadTypeRow
                        uploadFunc={uploadFolders}
                        Icon={FolderUploadIcon}
                        uploadName={constants.UPLOAD_DIRS}
                    />
                    <UploadTypeRow
                        uploadFunc={uploadGoogleTakeoutZips}
                        Icon={GoogleIcon}
                        uploadName={constants.UPLOAD_GOOGLE_TAKEOUT}
                    />
                </Container>
            </Modal.Body>
        </Modal>
    );
}
Example #12
Source File: CollectionSelector.tsx    From bada-frame with GNU General Public License v3.0 5 votes vote down vote up
function CollectionSelector({
    attributes,
    collectionsAndTheirLatestFile,
    ...props
}: Props) {
    const [collectionToShow, setCollectionToShow] = useState<
        CollectionAndItsLatestFile[]
    >([]);
    useEffect(() => {
        if (!attributes || !props.show) {
            return;
        }
        const user: User = getData(LS_KEYS.USER);
        const personalCollectionsOtherThanFrom =
            collectionsAndTheirLatestFile?.filter(
                (item) =>
                    item.collection.id !== attributes.fromCollection &&
                    item.collection.owner.id === user?.id &&
                    item.collection.type !== CollectionType.favorites
            );
        if (personalCollectionsOtherThanFrom.length === 0) {
            props.onHide();
            attributes.showNextModal();
        } else {
            setCollectionToShow(personalCollectionsOtherThanFrom);
        }
    }, [props.show]);

    if (!attributes) {
        return <Modal />;
    }
    const CollectionIcons: JSX.Element[] = collectionToShow?.map((item) => (
        <CollectionIcon
            key={item.collection.id}
            onClick={() => {
                attributes.callback(item.collection);
                props.onHide();
            }}>
            <CollectionCard>
                <PreviewCard file={item.file} forcedEnable />
                <Card.Text className="text-center">
                    {item.collection.name}
                </Card.Text>
            </CollectionCard>
        </CollectionIcon>
    ));

    return (
        <Modal
            {...props}
            size="xl"
            centered
            contentClassName="plan-selector-modal-content">
            <Modal.Header closeButton onHide={() => props.onHide(true)}>
                <Modal.Title>{attributes.title}</Modal.Title>
            </Modal.Header>
            <Modal.Body
                style={{
                    display: 'flex',
                    flexWrap: 'wrap',
                }}>
                <AddCollectionButton showNextModal={attributes.showNextModal} />
                {CollectionIcons}
            </Modal.Body>
        </Modal>
    );
}
Example #13
Source File: disclamer-btn.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 5 votes vote down vote up
DisclamerButton = (props: any) => {

    const { t } = useTranslation();
    const [show, setShow] = React.useState(false);

    React.useEffect(() => {
        setShow(props.firstTimeShow);
        props.onInit();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    return (
        <>
            <Image
                src={SpeechBubbleImage}
                className='speech-bubble'
                onClick={() => { setShow(true) }}
            />

            <Modal
                contentClassName='data-modal'
                show={show}
                backdrop={true}
                onHide={() => { setShow(false) }}
                keyboard={false}
                centered
            >
                <Modal.Header id='data-header' className='pb-0' >
                    <Row>
                        <Col >
                            <Card.Title className='m-0 jcc-xs-jcfs-md' as={'h2'} >
                                {t('translation:disclaimer-title')}</Card.Title>
                        </Col>
                    </Row>
                </Modal.Header>

                <Modal.Body className='bg-light py-0'>
                    <hr />
                    <h5 className='disclaimer-text'>
                        <Trans>{props.disclaimerText}</Trans>
                    </h5>

                    <hr />

                    <FormGroupConsentCkb controlId='formDoNotShowCheckbox' title={t('translation:disclaimer-do-not-show')}
                        onChange={(evt: any) => props.onCheckChange(evt.currentTarget.checked)}
                        type='checkbox'
                        checked={props.checked}
                    />
                </Modal.Body>

                <Modal.Footer id='data-footer'>
                    <Container className='p-0'>
                        <Row className='justify-content-end'>
                            <Col xs='6' className='p-0'>
                                <Button
                                    className='py-0'
                                    block
                                    onClick={() => { setShow(false) }}
                                >
                                    {t('translation:ok')}
                                </Button>
                            </Col>
                        </Row>
                    </Container>
                </Modal.Footer>
            </Modal>
        </>
    )
}
Example #14
Source File: StartUp.tsx    From 3Speak-app with GNU General Public License v3.0 5 votes vote down vote up
export function StartUp(props: any) {
  const [show, setShow] = useState(false)
  const [message, setMessage] = useState('')

  useEffect(() => {
    const load = async () => {
      const backendStatus = (await PromiseIpc.send('core.status', undefined as any)) as any
      if (backendStatus.ready === false) {
        setShow(true)
        const pid = setInterval(async () => {
          const status = (await PromiseIpc.send('core.status', undefined as any)) as any
          setMessage(status.start_progress.message)
        }, 25)
        PromiseIpc.send('core.ready', undefined as any).then((eda) => {
          setShow(false)
          clearInterval(pid)
        })
      }
    }

    void load()
  }, [])

  return (
    <div>
      <Modal show={show} backdrop={'static'} backdropClassName={'start-backdrop'}>
        <Modal.Header>
          <Modal.Title>App Starting Up</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div style={{ textAlign: 'center' }}>
            <h1 style={{ paddingTop: '50px' }}>Loading</h1>
            <hr />
            <p style={{ fontSize: '15px' }}>{message}</p>
          </div>
        </Modal.Body>
      </Modal>
    </div>
  )
}
Example #15
Source File: NetworkModal.tsx    From devex with GNU General Public License v3.0 5 votes vote down vote up
NetworkModal: React.FC<IProps> = ({ show, handleCloseModal, cb }) => {
  const themeContext = useContext(ThemeContext);
  const { theme } = themeContext!;
  const [networkUrlInput, setNetworkUrlInput] = useState("");
  const [networkNameInput, setNetworkNameInput] = useState("");

  const handleSubmit = (e: React.SyntheticEvent) => {
    e.preventDefault();
    cb(sanitizeHtml(networkUrlInput), sanitizeHtml(networkNameInput));
    setNetworkUrlInput("");
    setNetworkNameInput("");
  };

  return (
    <Modal
      className={
        theme === "dark"
          ? "custom-modal dark-theme"
          : "custom-modal light-theme"
      }
      show={show}
      onHide={handleCloseModal}
    >
      <div className="modal-header">
        <h6>Add Network</h6>
      </div>
      <Modal.Body>
        <Form onSubmit={handleSubmit}>
          <Form.Group>
            <div className="d-flex align-items-center mb-2">
              <FontAwesomeIcon className="mr-3" icon={faTag} />
              <Form.Control
                required
                type="text"
                value={networkNameInput}
                maxLength={20}
                onChange={(e) => {
                  setNetworkNameInput(e.target.value.toString());
                }}
                placeholder="Enter Name"
              />
            </div>
          </Form.Group>
          <Form.Group>
            <div className="d-flex align-items-center mb-4">
              <FontAwesomeIcon className="mr-3" icon={faLink} />
              <Form.Control
                required
                type="text"
                value={networkUrlInput}
                onChange={(e) => {
                  setNetworkUrlInput(e.target.value.toString());
                }}
                placeholder="Enter Url"
              />
            </div>
          </Form.Group>
          <div>
            <Button block type="submit">
              Save
            </Button>
          </div>
        </Form>
      </Modal.Body>
    </Modal>
  );
}
Example #16
Source File: PlayerActorConfigModal.tsx    From apps with MIT License 5 votes vote down vote up
render() {
        return (
            <Modal animation={false} show={this.props.open} size="xl" onHide={this.props.close}>
                <Modal.Header closeButton>
                    <Modal.Title>Servant Configuration</Modal.Title>
                </Modal.Header>

                <Modal.Body>
                    <Form>
                        <Form.Group>
                            <Form.Label>Name</Form.Label>
                            <Form.Control
                                type="text"
                                disabled={this.props.loading}
                                onBlur={this.props.validate}
                                onChange={(event) => this.setName(event.target.value)}
                                value={this.props.servantOptions?.name}
                            />
                        </Form.Group>
                        <Form.Group>
                            <Form.Label>Level</Form.Label>
                            <Form.Control
                                type="number"
                                disabled={this.props.loading}
                                onBlur={this.props.validate}
                                onChange={(event) => this.setLevel(event.target.value)}
                                value={this.props.servantOptions.level}
                            />
                        </Form.Group>
                    </Form>
                </Modal.Body>

                <Modal.Footer>
                    <Button variant="secondary" onClick={this.props.close}>
                        Close
                    </Button>
                    <Button variant="primary" onClick={this.props.add}>
                        Add
                    </Button>
                </Modal.Footer>
            </Modal>
        );
    }
Example #17
Source File: confirm-modal.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 5 votes vote down vote up
ConfirmModal = (props: any) => {
    const { t } = useTranslation();
    const [btnOkDisabled, setBtnOkDisabled] = React.useState(true);

    const handleEnter = () => {
        setBtnOkDisabled(false);
    }

    const handleOk = () => {
        if (props.handleOk) {
            setBtnOkDisabled(true);
            props.handleOk();
        }
    }

    return (
        <Modal
            contentClassName='data-modal'
            show={props.show}
            backdrop="static"
            keyboard={false}
            onEnter={handleEnter}
            centered
        >
            <Modal.Header id='data-header' className='pb-0' >
                <Card.Title className='m-0 jcc-xs-jcfs-md' as={'h3'} >{props.title}</Card.Title>
            </Modal.Header>
            <Modal.Body className='bg-light'>
                {props.message}
            </Modal.Body>
            <Modal.Footer id='data-footer'>

                <Container className='p-0'>
                    <Row>
                        <Col sm='6' lg='4' className='mb-2 mb-sm-0 p-0 pr-sm-2'>
                            <Button
                                className='p-0'
                                block
                                variant='outline-primary'
                                onClick={props.onCancel}
                            >
                                {t('translation:cancel')}
                            </Button>
                        </Col>
                        <Col sm='6' lg='4' className='p-0 pl-sm-2'>
                            <Button
                                className='p-0'
                                block
                                onClick={handleOk}
                                disabled={btnOkDisabled}
                            >
                                {t('translation:ok')}

                                <Spinner
                                    as="span"
                                    className='btn-spinner'
                                    animation="border"
                                    hidden={!btnOkDisabled}
                                    size="sm"
                                    role="status"
                                    aria-hidden="true"
                                />
                            </Button>
                        </Col>
                    </Row>
                </Container>
            </Modal.Footer>
        </Modal>
    )
}
Example #18
Source File: error-page.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 5 votes vote down vote up
ErrorPage = (props: any) => {

    const { t } = useTranslation();
    const [show, setShow] = React.useState(true);

    React.useEffect(() => {
        if (props)
            setShow(props.show);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [props.show])

    return (
        <>
            <Modal
                contentClassName='data-modal'
                show={show}
                backdrop="static"
                keyboard={false}
                onExited={props.onExit}
                centered
            >
                <Modal.Header id='data-header' className='pb-0' >
                    <Row>
                        <Col >
                            <Card.Title className='m-0 jcc-xs-jcfs-md' as={'h2'} >{t('translation:error-message')}</Card.Title>
                        </Col>
                    </Row>
                </Modal.Header>

                {/*
    content area with process number input and radios
    */}
                <Modal.Body className='py-0 bg-light'>
                    <hr />
                    <p className='text-center'>
                        <span className='font-weight-bold'>{t('translation:serverError')}</span>
                        <span>{props?.error ? props?.error?.message : props.message}</span>
                    </p>

                    <hr />
                </Modal.Body>

                {/*
    footer with cancel and submit button
    */}
                <Modal.Footer id='data-footer'>
                    <Button
                        className='py-0'
                        onClick={() => { props.onCancel(); props.onHide(); }}
                    >
                        {t('translation:cancel')}
                    </Button>
                </Modal.Footer>
            </Modal>
        </>
    )
}
Example #19
Source File: dataprivacy.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
DataprivacyPage = (props: any) => {

    const { t } = useTranslation();
    const [show, setShow] = React.useState(false);

    React.useEffect(() => {
        if (props)
            setShow(props.show);
            // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [props.show])

    const handleClose = () => {
        props.setShow(false)
    }

    return (
        <>
            <Modal
                size='lg'
                contentClassName='bg-light'
                scrollable
                show={show}
                aria-labelledby="example-custom-modal-styling-title"
                centered
                onHide={handleClose}

            >
                <Modal.Header id='data-header' closeButton className='pb-0' >
                    <Row>
                        <Col >
                            <Card.Title className='m-0 jcc-xs-jcfs-md' as={'h2'} >{t('translation:dp-title')}</Card.Title>
                        </Col>
                    </Row>
                </Modal.Header>
                    <hr className='mx-3 mb-0' />
                <Modal.Body className='px-3 bg-light'>
                    <Container className='px-1 px-sm-2 px-md-3'>
                        <h5 className='text-justify'>
                            Der Schutz Ihrer persönlichen Daten hat für die T-Systems International GmbH einen hohen Stellenwert. Es ist uns wichtig, Sie darüber zu informieren, welche persönlichen Daten erfasst werden, wie diese verwendet werden und welche Gestaltungsmöglichkeiten Sie dabei haben.
                    </h5>

                        <ol>
                            <li className='text-justify py-3'>
                                <strong>Welche Daten werden erfasst, wie werden sie verwendet und wie lange werden sie gespeichert?</strong>
                                <ol type='a' className='pr-2 pr-md-4'>
                                    <li>
                                        <strong>Technische Merkmale:</strong> <br />
                                        Wenn Sie sich an unserem Schnelltestportal anmelden, verzeichnet der Server Ihren Benutzernamen, die Teststellen-ID, den verwendeten Mandanten (und die von Ihnen ausgeführten Datenbankoperationen (z.B. Eingabe von Patientendaten, Eingabe von Testergebnissen). 
Die protokollierten Daten werden ausschließlich für Zwecke der Datensicherheit, insbesondere zur Abwehr von Angriffsversuchen auf unseren Server verwendet (Art. 6 Abs. 1f DSGVO). Sie werden weder für die Erstellung von individuellen Anwenderprofilen verwendet noch an Dritte weitergegeben und werden nach Ablauf eines Zeitraums von 7 Tagen bis 30 Tagen gelöscht. Die statistische Auswertung anonymisierter Datensätze behalten wir uns vor.<br />
                                    </li>
                                    <li className='py-3'>
                                        <strong>Authentifizierungsdaten:</strong> <br />
                                        Wenn Sie sich an unserem Schnelltest-Portal anmelden, werden erfolgreiche und fehlgeschlagene Anmeldeversuche dokumentiert. Diese Dokumentation umfasst den Benutzernamen, Ihren Vor- und Nachnamen, den Zeitpunkt der Anmeldung, die IP-Adresse, von der aus die Anmeldung durchgeführt wurde und die Session-Dauer. Rechtsgrundlage dieser Verarbeitung ist § 26 Abs. 1 BDSG, soweit Sie als Beschäftigter eines Unternehmens, welches unsere Leistungen in Anspruch nimmt, tätig sind. Sind Sie auf selbständiger Basis für ein Unternehmen tätig, welches unsere Leistungen in Anspruch nimmt, erfolgt die Verarbeitung auf Grund der durch Ihren Auftraggeber eingeholten Einwilligung zur Speicherung.<br />
                                    </li>
                                    <li>
                                        <strong>Archivierung von Testergebnissen:</strong> <br />
                                        Ihr Benutzername wird zusammen mit den Patientendaten des durchgeführten Tests (Name, Vorname, Geburtsdatum, Geschlecht, Adresse, Testhersteller, eingesetzter Test, Tag des Testergebnisses) und dem Testergebnis gemäß gesetzlicher Grundlage archiviert und 10 Jahre aufbewahrt und dann gelöscht.<br />
                                    </li>
                                </ol>
                            </li>
                            <li className='text-justify py-3' >
                                <strong>Wird mein Nutzungsverhalten ausgewertet, z. B. für Werbung oder Tracking?<br /></strong>
                                Es werden nur für die Nutzung des Schnelltest-Portals erforderliche Cookies verwendet. Diese Cookies sind notwendig, damit Sie durch die Seiten navigieren und wesentliche Funktionen nutzen können. Sie ermöglichen die Benutzung des Schnelltestportals. Rechtsgrundlage für diese Cookies ist Art. 6 Abs. 1b DSGVO bzw. bei Drittstaaten Art. 49 Abs. 1b DSGVO.
                             
                            </li>
                            <Table className='my-3'>
                                <thead>
                                    <tr>
                                        <th>Firma</th>
                                        <th>Zweck</th>
                                        <th>Speicherdauer</th>
                                        <th>Land der Verarbeitung</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td>T-Systems</td>
                                        <td>Login</td>
                                        <td>Session Cookie</td>
                                        <td>Deutschland</td>
                                    </tr>
                                </tbody>
                            </Table>
                            <li className='text-justify py-3' >
                                <strong>Wo finde ich die Informationen, die für mich wichtig sind?</strong><br />
                                Dieser <strong>Datenschutzhinweis</strong> gibt einen Überblick über die Punkte, die für die Verarbeitung Ihrer Daten in diesem Webportal durch T-Systems gelten.<br />
Weitere Informationen, auch zum Datenschutz im allgemeinen und in speziellen Produkten, erhalten Sie auf <a href='https://www.telekom.com/de/verantwortung/datenschutz-und-datensicherheit/datenschutz'>https://www.telekom.com/de/verantwortung/datenschutz-und-datensicherheit/datenschutz</a> und unter <a href='http://www.telekom.de/datenschutzhinweise'>http://www.telekom.de/datenschutzhinweise</a>.
                            </li>
                            <li className='text-justify py-3' >
                                <strong>Wer ist verantwortlich für die Datenverarbeitung? Wer ist mein Ansprechpartner, wenn ich Fragen zum Datenschutz bei der Telekom habe?</strong><br />
                                Datenverantwortliche ist die T-Systems International GmbH. Bei Fragen können Sie sich an unseren <a href='http://www.telekom.de/kontakt'>Kundenservice</a> wenden oder an unseren Datenschutzbeauftragten, Herrn Dr. Claus D. Ulmer, Friedrich-Ebert-Allee 140, 53113 Bonn, <a href='mailto:[email protected]'>[email protected]</a>.
                            </li>
                            <li className='text-justify py-3' >
                                <strong>Welche Rechte habe ich? </strong><br />
                                Sie haben das Recht,
                                <ol type='a' className='pr-2 pr-md-4'>
                                    <li>
                                        <strong>Auskunft</strong> zu verlangen zu Kategorien der verarbeiteten Daten, Verarbeitungszwecken, etwaigen Empfängern der Daten, der geplanten Speicherdauer (Art. 15 DSGVO);
                                    </li>
                                    <li>
                                        die <strong>Berichtigung</strong> bzw. Ergänzung unrichtiger bzw. unvollständiger Daten zu verlangen (Art. 16 DSGVO);
                                    </li>
                                    <li>
                                        eine erteilte Einwilligung jederzeit mit Wirkung für die Zukunft zu <strong>widerrufen</strong> (Art. 7 Abs. 3 DSGVO);
                                    </li>
                                    <li>
                                        einer Datenverarbeitung, die aufgrund eines berechtigten Interesses erfolgen soll, aus Gründen zu <strong>widersprechen</strong>, die sich aus Ihrer besonderen Situation ergeben (Art 21 Abs. 1 DSGVO);
                                    </li>
                                    <li>
                                        in bestimmten Fällen im Rahmen des Art. 17 DSGVO die <strong>Löschung</strong> von Daten zu verlangen - insbesondere soweit die Daten für den vorgesehenen Zweck nicht mehr erforderlich sind bzw. unrechtmäßig verarbeitet werden, oder Sie Ihre Einwilligung gemäß oben (c) widerrufen oder einen Widerspruch gemäß oben (d) erklärt haben;
                                    </li>
                                    <li>
                                        unter bestimmten Voraussetzungen die <strong>Einschränkung</strong> von Daten zu verlangen, soweit eine Löschung nicht möglich bzw. die Löschpflicht streitig ist (Art. 18 DSGVO);
                                    </li>
                                    <li>
                                        auf <strong>Datenübertragbarkeit</strong>, d.h. Sie können Ihre Daten, die Sie uns bereitgestellt haben, in einem gängigen maschinenlesbaren Format, wie z.B. CSV, erhalten und ggf. an andere übermitteln (Art. 20 DSGVO);
                                    </li>
                                    <li>
                                        sich bei der zuständigen <strong>Aufsichtsbehörde</strong> über die Datenverarbeitung zu <strong>beschweren</strong> (für Telekommunikationsverträge: Bundesbeauftragter für den Datenschutz und die Informationsfreiheit; im Übrigen: Landesbeauftragte für den Datenschutz und die Informationsfreiheit Nordrhein-Westfalen).
                                    </li>
                                </ol>
                            </li>

                            <li className='text-justify py-3' >
                                <strong>An wen gibt die Telekom meine Daten weiter?</strong><br />
                                <strong>An Auftragsverarbeiter</strong>, das sind Unternehmen, die wir im gesetzlich vorgesehenen Rahmen mit der Verarbeitung von Daten beauftragen, Art. 28 DSGVO (Dienstleister, Erfüllungsgehilfen). Die Telekom bleibt auch in dem Fall weiterhin für den Schutz Ihrer Daten verantwortlich. Wir beauftragen Unternehmen insbesondere in folgenden Bereichen: IT, Vertrieb, Marketing, Finanzen, Beratung, Kundenservice, Personalwesen, Logistik, Druck.<br />
                                <strong>Aufgrund gesetzlicher Verpflichtung</strong>: In bestimmten Fällen sind wir gesetzlich verpflichtet, bestimmte Daten an die anfragende staatliche Stelle zu übermitteln.
                            </li>
                            <li className='text-justify py-3' >
                                <strong>Wo werden meine Daten verarbeitet?</strong><br />
                                Ihre Daten werden in Deutschland und im europäischen Ausland verarbeitet. Findet eine Verarbeitung Ihrer Daten in Ausnahmefällen auch in Ländern außerhalb der Europäischen Union (in sog. Drittstaaten) statt, geschieht dies,
                                <ol type='a' className='pr-2 pr-md-4'>
                                    <li>
                                    soweit Sie hierin ausdrücklich eingewilligt haben (Art. 49 Abs. 1a DSGVO).  (In den meisten Ländern außerhalb der EU entspricht das Datenschutzniveau nicht den EU Standards. Dies betrifft insbesondere umfassende Überwachungs- und Kontrollrechte staatlicher Behörden, z.B. in den USA, die in den Datenschutz der europäischen Bürgerinnen und Bürger unverhältnismäßig eingreifen,
                                    </li>
                                    <li>
                                    oder soweit es für unsere Leistungserbringung Ihnen gegenüber erforderlich ist (Art. 49 Abs. 1b DSGVO),
                                    </li>
                                    <li>
                                    oder soweit es gesetzlich vorgesehen ist (Art. 6 Abs. 1c DSGVO).
                                    </li>
                                </ol>
                                Darüber hinaus erfolgt eine Verarbeitung Ihrer Daten in Drittstaaten nur, soweit durch bestimmte Maßnahmen sichergestellt ist, dass hierfür ein angemessenes Datenschutzniveau besteht (z.B. Angemessenheitsbeschluss der EU-Kommission oder sog. geeignete Garantien, Art. 44ff. DSGVO).<br/><br/>
                                Stand der Datenschutzhinweise 29.04.2021
                            </li>
                        </ol>
                    </Container>
                </Modal.Body>
                    <hr className='mx-3 mt-0' />

                {/*
    footer with ok button
    */}
                <Modal.Footer id='data-footer'>
                    <Button
                        className='py-0'
                        onClick={handleClose}
                    >
                        {t('translation:cancel')}
                    </Button>
                </Modal.Footer>
            </Modal>
        </>
    )
}
Example #20
Source File: Navigation.tsx    From apps with MIT License 4 votes vote down vote up
render() {
        return (
            <>
                <Navbar id={"navigation"} bg={"dark"} variant={"dark"} expand={"lg"}>
                    <Container fluid>
                        <Navbar.Brand as={Link} to="/" title="Atlas Academy Database">
                            Atlas Academy DB
                        </Navbar.Brand>
                        <Navbar.Toggle />

                        <Navbar.Collapse>
                            <Nav activeKey={this.props.location.pathname}>
                                <NavPage path="servants" description="Servants" />
                                <NavPage path="craft-essences" description="Craft Essences" />
                                <NavPage path="wars" description="Wars" />
                                <NavDropdown title="Other" id="dropdown-other">
                                    <NavDropdownPage path="command-codes" description="Command Codes" />
                                    <NavDropdownPage path="mystic-codes" description="Mystic Codes" />
                                    <NavDropdownPage path="items" description="Materials" />
                                    <NavDropdownPage path="events" description="Events" />
                                    <NavDropdownPage path="bgms" description="BGMs" />
                                    <NavDropdownPage path="master-missions" description="Master Missions" />
                                </NavDropdown>
                                <NavDropdown title="Search" id="dropdown-search">
                                    <NavDropdownPage path="entities" description="Entities" />
                                    <NavDropdownPage path="skills" description="Skills" />
                                    <NavDropdownPage path="noble-phantasms" description="Noble Phantasms" />
                                    <NavDropdownPage path="funcs" description="Functions" />
                                    <NavDropdownPage path="buffs" description="Buffs" />
                                    <NavDropdownPage path="quests" description="Quests" />
                                    <NavDropdownPage path="scripts" description="Scripts" />
                                </NavDropdown>
                                <NavDropdown title="Changelog" id="dropdown-search">
                                    <NavDropdownPage path="changes" description="Master Data" />
                                    <NavDropdownPage path="enemy-changes" description="Enemy Data" />
                                </NavDropdown>
                            </Nav>
                            <Nav className={"ml-auto icons"} activeKey="">
                                <Row>
                                    <Col>
                                        <Link
                                            to={this.regionLink(Region.JP)}
                                            className={`nav-link ${this.regionClass(Region.JP)}`}
                                        >
                                            <JPFlag title="View data from the JP version" />
                                        </Link>
                                    </Col>
                                    <Col>
                                        <Link
                                            to={this.regionLink(Region.NA)}
                                            className={`nav-link ${this.regionClass(Region.NA)}`}
                                        >
                                            <USFlag title="View data from the NA version" />
                                        </Link>
                                    </Col>
                                    <Col>
                                        <Link
                                            to={this.regionLink(Region.CN)}
                                            className={`nav-link ${this.regionClass(Region.CN)}`}
                                        >
                                            <CNFlag title="View data from the CN version" />
                                        </Link>
                                    </Col>
                                    <Col>
                                        <Link
                                            to={this.regionLink(Region.KR)}
                                            className={`nav-link ${this.regionClass(Region.KR)}`}
                                        >
                                            <KRFlag title="View data from the KR version" />
                                        </Link>
                                    </Col>
                                    <Col>
                                        <Link
                                            to={this.regionLink(Region.TW)}
                                            className={`nav-link ${this.regionClass(Region.TW)}`}
                                        >
                                            <TWFlag title="View data from the TW version" />
                                        </Link>
                                    </Col>
                                </Row>
                                <Row>
                                    <Col>
                                        <Nav.Link
                                            href="https://atlasacademy.io/discord"
                                            target="_blank"
                                            rel="noreferrer"
                                        >
                                            <FontAwesomeIcon icon={faDiscord} title="Atlas Academy Discord" />
                                        </Nav.Link>
                                    </Col>
                                    <Col>
                                        <Nav.Link
                                            href="https://twitter.com/aacademy_fgo"
                                            target="_blank"
                                            rel="noreferrer"
                                        >
                                            <FontAwesomeIcon icon={faTwitter} title="Atlas Academy Twitter" />
                                        </Nav.Link>
                                    </Col>
                                    <Col>
                                        <Nav.Link
                                            href="https://github.com/atlasacademy/apps"
                                            target="_blank"
                                            rel="noreferrer"
                                        >
                                            <FontAwesomeIcon icon={faGithub} title="Atlas Academy DB Github" />
                                        </Nav.Link>
                                    </Col>
                                </Row>
                                <Button variant={"primary"} onClick={() => this.showSettings()}>
                                    <FontAwesomeIcon icon={faCog} title="Settings" />
                                </Button>
                            </Nav>
                        </Navbar.Collapse>
                    </Container>
                </Navbar>

                <Modal show={this.state.showSettings} onHide={() => this.hideSettings()}>
                    <Modal.Header>
                        <Modal.Title>Settings</Modal.Title>
                        <button className="modal-close" onClick={() => this.hideSettings()}>
                            <FontAwesomeIcon icon={faXmark} title="Close Settings" />
                        </button>
                    </Modal.Header>
                    <Modal.Body>
                        <SettingForm language={this.props.language} theme={this.props.theme} />
                    </Modal.Body>
                </Modal>
            </>
        );
    }
Example #21
Source File: index.tsx    From nouns-monorepo with GNU General Public License v3.0 4 votes vote down vote up
ProposalTransactionFormModal = ({
  show,
  onHide,
  onProposalTransactionAdded,
}: ProposalTransactionFormModalProps) => {
  const [address, setAddress] = useState('');
  const [abi, setABI] = useState<Interface>();
  const [value, setValue] = useState('');
  const [func, setFunction] = useState('');
  const [args, setArguments] = useState<string[]>([]);

  const [isABIUploadValid, setABIUploadValid] = useState<boolean>();
  const [abiFileName, setABIFileName] = useState<string | undefined>('');

  const addressValidator = (s: string) => {
    if (!utils.isAddress(s)) {
      return false;
    }
    // To avoid blocking stepper progress, do not `await`
    populateABIIfExists(s);
    return true;
  };

  const valueValidator = (v: string) => !v || !new BigNumber(v).isNaN();

  const argumentsValidator = (a: string[]) => {
    if (!func) {
      return true;
    }

    try {
      return !!abi?._encodeParams(abi?.functions[func]?.inputs, args);
    } catch {
      return false;
    }
  };

  const setArgument = (index: number, value: string) => {
    const values = [...args];
    values[index] = value;
    setArguments(values);
  };

  let abiErrorTimeout: NodeJS.Timeout;
  const setABIInvalid = () => {
    setABIUploadValid(false);
    setABIFileName(undefined);
    abiErrorTimeout = setTimeout(() => {
      setABIUploadValid(undefined);
    }, 5_000);
  };

  const validateAndSetABI = (file: File | undefined) => {
    if (abiErrorTimeout) {
      clearTimeout(abiErrorTimeout);
    }
    if (!file) {
      return;
    }

    const reader = new FileReader();
    reader.onload = async e => {
      try {
        const abi = e?.target?.result?.toString() ?? '';
        setABI(new Interface(JSON.parse(abi)));
        setABIUploadValid(true);
        setABIFileName(file.name);
      } catch {
        setABIInvalid();
      }
    };
    reader.readAsText(file);
  };

  const getContractInformation = async (address: string) => {
    const response = await fetch(buildEtherscanApiQuery(address));
    const json = await response.json();
    return json?.result?.[0];
  };

  const getABI = async (address: string) => {
    let info = await getContractInformation(address);
    if (info?.Proxy === '1' && utils.isAddress(info?.Implementation)) {
      info = await getContractInformation(info.Implementation);
    }
    return info.ABI;
  };

  const populateABIIfExists = async (address: string) => {
    if (abiErrorTimeout) {
      clearTimeout(abiErrorTimeout);
    }

    try {
      const result = await getABI(address);
      setABI(new Interface(JSON.parse(result)));
      setABIUploadValid(true);
      setABIFileName('etherscan-abi-download.json');
    } catch {
      setABIUploadValid(undefined);
      setABIFileName(undefined);
    }
  };

  const stepForwardOrCallback = () => {
    if (currentStep !== steps.length - 1) {
      return stepForward();
    }
    onProposalTransactionAdded({
      address,
      value: value ? utils.parseEther(value).toString() : '0',
      signature: func,
      calldata: (func && abi?._encodeParams(abi?.functions[func]?.inputs, args)) || '0x',
    });
    clearState();
  };

  const steps = [
    {
      label: 'Address',
      name: 'address',
      validator: () => addressValidator(address),
    },
    {
      label: 'Value',
      name: 'value',
      validator: () => valueValidator(value),
    },
    {
      label: 'Function',
      name: 'function',
    },
    {
      label: 'Arguments',
      name: 'arguments',
      validator: () => argumentsValidator(args),
    },
    {
      label: 'Summary',
      name: 'summary',
    },
  ];

  const { stepForward, stepBackwards, currentStep } = useStepProgress({
    steps,
    startingStep: 0,
  });

  const clearState = () => {
    setAddress('');
    setABI(undefined);
    setValue('');
    setFunction('');
    setArguments([]);
    setABIUploadValid(undefined);
    setABIFileName(undefined);

    for (let i = currentStep; i > 0; i--) {
      stepBackwards();
    }
  };

  return (
    <Modal
      show={show}
      onHide={() => {
        onHide();
        clearState();
      }}
      dialogClassName={classes.transactionFormModal}
      centered
    >
      <Modal.Header closeButton>
        <Modal.Title>
          <Trans>Add a Proposal Transaction</Trans>
        </Modal.Title>
      </Modal.Header>
      <Modal.Body>
        <StepProgressBar className={classes.stepProgressBar} steps={steps} />
        <Step step={0}>
          <label htmlFor="callee-address">
            <Trans>Address (Callee or Recipient)</Trans>
          </label>
          <FormControl
            value={address}
            type="text"
            id="callee-address"
            onChange={e => setAddress(e.target.value)}
          />
        </Step>
        <Step step={1}>
          <label htmlFor="eth-value">
            <Trans>Value in ETH (Optional)</Trans>
          </label>
          <FormControl value={value} id="eth-value" onChange={e => setValue(e.target.value)} />
        </Step>
        <Step step={2}>
          <label htmlFor="function">
            <Trans>Function (Optional)</Trans>
          </label>
          <FormControl
            value={func}
            as="select"
            id="function"
            onChange={e => setFunction(e.target.value)}
          >
            <option className="text-muted">Select Contract Function</option>
            {abi && Object.keys(abi.functions).map(func => <option value={func}>{func}</option>)}
          </FormControl>
          <label style={{ marginTop: '1rem' }} htmlFor="import-abi">
            {abiFileName === 'etherscan-abi-download.json' ? abiFileName : 'ABI'}
          </label>
          <Form.Control
            type="file"
            id="import-abi"
            accept="application/JSON"
            isValid={isABIUploadValid}
            isInvalid={isABIUploadValid === false}
            onChange={(e: ChangeEvent<HTMLInputElement>) => validateAndSetABI(e.target.files?.[0])}
          />
        </Step>
        <Step step={3}>
          {abi?.functions[func]?.inputs?.length ? (
            <FormGroup as={Row}>
              {abi?.functions[func]?.inputs.map((input, i) => (
                <>
                  <FormLabel column sm="3">
                    {input.name}
                  </FormLabel>
                  <Col sm="9">
                    <InputGroup className="mb-2">
                      <InputGroup.Text className={classes.inputGroupText}>
                        {input.type}
                      </InputGroup.Text>
                      <FormControl
                        value={args[i] ?? ''}
                        onChange={e => setArgument(i, e.target.value)}
                      />
                    </InputGroup>
                  </Col>
                </>
              ))}
            </FormGroup>
          ) : (
            <Trans>No arguments required </Trans>
          )}
        </Step>
        <Step step={4}>
          <Row>
            <Col sm="3">
              <b>
                <Trans>Address</Trans>
              </b>
            </Col>
            <Col sm="9" className="text-break">
              <a href={buildEtherscanAddressLink(address)} target="_blank" rel="noreferrer">
                {address}
              </a>
            </Col>
          </Row>
          <Row>
            <Col sm="3">
              <b>
                <Trans>Value</Trans>
              </b>
            </Col>
            <Col sm="9">{value ? `${value} ETH` : <Trans>None</Trans>}</Col>
          </Row>
          <Row>
            <Col sm="3">
              <b>
                <Trans>Function</Trans>
              </b>
            </Col>
            <Col sm="9" className="text-break">
              {func || <Trans>None</Trans>}
            </Col>
          </Row>
          <Row>
            <Col sm="3">
              <b>
                <Trans>Arguments</Trans>
              </b>
            </Col>
            <Col sm="9">
              <hr />
            </Col>
            <Col sm="9">{abi?.functions[func]?.inputs?.length ? '' : <Trans>None</Trans>}</Col>
          </Row>
          {abi?.functions[func]?.inputs.map((input, i) => (
            <Row key={i}>
              <Col sm="3" className={classes.functionName}>
                {i + 1}. {input.name}
              </Col>
              <Col sm="9" className="text-break">
                {args[i]}
              </Col>
            </Row>
          ))}
        </Step>
        <div className="d-flex justify-content-between align-items-center pt-3">
          <Button
            onClick={stepBackwards}
            variant="outline-secondary"
            size="lg"
            disabled={currentStep === 0}
          >
            <Trans>Back</Trans>
          </Button>
          <Button onClick={stepForwardOrCallback} variant="primary" size="lg">
            {currentStep !== steps.length - 1 ? (
              <Trans>Next</Trans>
            ) : (
              <Trans>Add Transaction</Trans>
            )}
          </Button>
        </div>
      </Modal.Body>
    </Modal>
  );
}
Example #22
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
AccountModal = ({
  open,
  onClose
}: Props): JSX.Element => {
  const {
    polkaBtcLoaded,
    address,
    extensions
  } = useSelector((state: StoreType) => state.general);
  const { t } = useTranslation();
  const dispatch = useDispatch();

  const [accounts, setAccounts] = React.useState<InjectedAccountWithMeta[]>();

  React.useEffect(() => {
    if (!extensions.length) return;

    (async () => {
      try {
        const theAccounts = await web3Accounts();
        setAccounts(theAccounts);
      } catch (error) {
        // TODO: should add error handling properly
        console.log('[AccountModal] error.message => ', error.message);
      }
    })();
  }, [extensions.length]);

  const handleAccountSelect = (newAddress: string) => async () => {
    if (!polkaBtcLoaded) {
      return;
    }

    // TODO: should check when the app being initialized (not check everywhere)
    await web3Enable(APP_NAME);
    const { signer } = await web3FromAddress(newAddress);
    window.polkaBTC.setAccount(newAddress, signer);
    dispatch(changeAddressAction(newAddress));

    onClose();
  };

  return (
    <Modal
      show={open}
      onHide={onClose}
      size='lg'>
      <Modal.Header closeButton>
        <Modal.Title>
          {extensions.length ? 'Select account' : 'Pick a wallet'}
        </Modal.Title>
      </Modal.Header>
      <Modal.Body className='account-modal'>
        {extensions.length ? (
          <>
            {/* Create a new account when no accounts are available */}
            {!accounts?.length && (
              <p className='mb-4'>
                {t('no_account')}
                <InterlayLink
                  href={POLKADOT_EXTENSION}
                  target='_blank'
                  rel='noopener noreferrer'>
                  &nbsp;{t('here')}
                </InterlayLink>
                .
              </p>
            )}
            {/* List all available accounts */}
            <ul className='space-y-4'>
              {accounts?.map(account => (
                <li
                  key={account.address}
                  className={clsx(
                    'rounded',
                    'border',
                    'border-solid',
                    'shadow-sm',
                    'hover:bg-gray-100'
                  )}>
                  <button
                    className={clsx(
                      'p-4',
                      'flex',
                      'items-center',
                      'space-x-1.5',
                      'w-full'
                    )}
                    onClick={handleAccountSelect(account.address)}>
                    <span
                      className={clsx(
                        'rounded-full',
                        'h-3',
                        'w-3',
                        'inline-block',
                        address === account.address ? 'bg-green-500' : 'bg-transparent'
                      )} />
                    <span className='font-medium'>
                      {account.meta.name}
                    </span>
                    <span>
                      {`(${shortAddress(account.address)})`}
                    </span>
                  </button>
                </li>
              ))}
            </ul>
          </>
        ) : (
          <>
            <p className='mb-4'>
              {t('install_supported_wallets')}
            </p>
            <InterlayLink
              className={clsx(
                'flex',
                'items-center',
                'px-4',
                'py-2.5',
                'rounded',
                'shadow-sm',
                'border',
                'border-solid',
                'border-interlayRose',
                'w-1/2'
              )}
              href={POLKADOT_EXTENSION}
              target='_blank'
              rel='noopener noreferrer'>
              <PolkadotExtensionLogoIcon
                width={30}
                height={30} />
              <span style={{ marginLeft: 16 }}>Polkadot.js</span>
            </InterlayLink>
          </>
        )}
      </Modal.Body>
      <Modal.Footer>
        <Button
          variant='secondary'
          onClick={onClose}>
          Close
        </Button>
      </Modal.Footer>
    </Modal>
  );
}
Example #23
Source File: update-collateral.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
export default function UpdateCollateralModal(props: UpdateCollateralProps): JSX.Element {
  const { polkaBtcLoaded, vaultClientLoaded, address } = useSelector((state: StoreType) => state.general);
  const { register, handleSubmit, errors } = useForm<UpdateCollateralForm>();
  // denoted in DOT
  const currentDOTCollateral = useSelector((state: StoreType) => state.vault.collateral);
  // denoted in DOT
  const [newCollateral, setNewCollateral] = useState('');
  // denoted in DOT
  const [currentCollateral, setCurrentCollateral] = useState('');
  const [newCollateralization, setNewCollateralization] = useState('∞');

  const [currentButtonText, setCurrentButtonText] = useState('');

  const [isUpdatePending, setUpdatePending] = useState(false);
  const [isCollateralUpdateAllowed, setCollateralUpdateAllowed] = useState(false);
  const dispatch = useDispatch();
  const { t } = useTranslation();

  const onSubmit = handleSubmit(async () => {
    if (!polkaBtcLoaded) return;
    if (!vaultClientLoaded) return;

    setUpdatePending(true);
    try {
      const newCollateralBig = new Big(newCollateral);
      const currentCollateralBig = new Big(currentCollateral);

      if (currentCollateralBig.gt(newCollateralBig)) {
        const withdrawAmount = currentCollateralBig.sub(newCollateralBig);
        await window.polkaBTC.vaults.withdrawCollateral(withdrawAmount);
      } else if (currentCollateralBig.lt(newCollateralBig)) {
        const depositAmount = newCollateralBig.sub(currentCollateralBig);
        await window.polkaBTC.vaults.lockAdditionalCollateral(depositAmount);
      } else {
        closeModal();
        return;
      }

      const vaultId = window.polkaBTC.api.createType(ACCOUNT_ID_TYPE_NAME, address);
      const balanceLockedDOT = await window.polkaBTC.collateral.balanceLocked(vaultId);
      dispatch(updateCollateralAction(balanceLockedDOT.toString()));
      let collateralization;
      try {
        collateralization = new Big(parseFloat(newCollateralization) / 100);
      } catch {
        collateralization = undefined;
      }
      dispatch(updateCollateralizationAction(collateralization?.mul(100).toString()));

      toast.success(t('vault.successfully_updated_collateral'));
      closeModal();
    } catch (error) {
      toast.error(error.toString());
    }
    setUpdatePending(false);
  });

  const closeModal = () => {
    props.onClose();
    setNewCollateralization('');
  };

  const onChange = async (obj: SyntheticEvent) => {
    try {
      const value = (obj.target as HTMLInputElement).value;
      if (value === '' || !polkaBtcLoaded || Number(value) <= 0 || isNaN(Number(value)) || !vaultClientLoaded) {
        setCollateralUpdateAllowed(false);
        return;
      }

      if (!dotToPlanck(value)) {
        throw new Error('Please enter an amount greater than 1 Planck');
      }

      // decide if we withdraw or add collateral
      if (!currentDOTCollateral) {
        throw new Error('Couldn\'t fetch current vault collateral');
      }
      setCurrentCollateral(currentDOTCollateral);

      let newCollateral = new Big(currentDOTCollateral);
      if (props.status === CollateralUpdateStatus.Increase) {
        newCollateral = newCollateral.add(new Big(value));
      } else if (props.status === CollateralUpdateStatus.Decrease) {
        newCollateral = newCollateral.sub(new Big(value));
      }
      setNewCollateral(newCollateral.toString());

      const vaultId = window.polkaBTC.api.createType(ACCOUNT_ID_TYPE_NAME, address);
      const requiredCollateral = (await window.polkaBTC.vaults.getRequiredCollateralForVault(vaultId)).toString();

      // collateral update only allowed if above required collateral
      const allowed = newCollateral.gte(new Big(requiredCollateral));
      setCollateralUpdateAllowed(allowed);

      // get the updated collateralization
      const newCollateralization = await window.polkaBTC.vaults.getVaultCollateralization(vaultId, newCollateral);
      if (newCollateralization === undefined) {
        setNewCollateralization('∞');
      } else {
        // The vault API returns collateralization as a regular number rather than a percentage
        setNewCollateralization(newCollateralization.mul(100).toString());
      }
    } catch (err) {
      console.log(err);
    }
  };

  const getButtonVariant = (status: CollateralUpdateStatus): string => {
    switch (status) {
    case CollateralUpdateStatus.Increase:
      return 'outline-success';
    case CollateralUpdateStatus.Decrease:
      return 'outline-danger';
    default:
      return '';
    }
  };

  function getStatusText(status: CollateralUpdateStatus): string {
    switch (status) {
    case CollateralUpdateStatus.Increase:
      if (currentButtonText !== t('vault.increase_collateral')) {
        setCurrentButtonText(t('vault.increase_collateral'));
      }
      return t('vault.increase_collateral');
    case CollateralUpdateStatus.Decrease:
      if (currentButtonText !== t('vault.withdraw_collateral')) {
        setCurrentButtonText(t('vault.withdraw_collateral'));
      }
      return t('vault.withdraw_collateral');
    default:
      return currentButtonText || '';
    }
  }

  return (
    <Modal
      show={props.status !== CollateralUpdateStatus.Hidden}
      onHide={closeModal}>
      <form onSubmit={onSubmit}>
        <Modal.Header closeButton>
          <Modal.Title>{getStatusText(props.status)}</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className='row'>
            <div className='col-12 current-collateral'>
              {t('vault.current_total_collateral', { currentDOTCollateral })}
            </div>
            <div className='col-12'>
              {t('vault.update_collateral')}
            </div>
            <div className='col-12 basic-addon'>
              <div className='input-group'>
                <input
                  name='collateral'
                  type='float'
                  className={'form-control custom-input' + (errors.collateral ? ' error-borders' : '')}
                  aria-describedby='basic-addon2'
                  ref={register({
                    required: true,
                    min: 0
                  })}
                  onChange={onChange}>
                </input>
                <div className='input-group-append'>
                  <span
                    className='input-group-text'
                    id='basic-addon2'>
                    DOT
                  </span>
                </div>
              </div>
              {errors.collateral && (
                <div className='input-error'>
                  {errors.collateral.type === 'required' ?
                    t('vault.collateral_is_required') :
                    errors.collateral.message}
                  {errors.collateral.type === 'min' ? t('vault.collateral_higher_than_0') : errors.collateral.message}
                </div>
              )}
            </div>
            <div className='col-12'>
              {t('vault.new_collateralization')}
              {
                // eslint-disable-next-line no-negated-condition
                newCollateralization !== '∞' ?
                  Number(newCollateralization) > 1000 ?
                    ' more than 1000%' :
                    ' ' + roundTwoDecimals(newCollateralization || '0') + '%' :
                  ' ' + newCollateralization
              }
            </div>
          </div>
        </Modal.Body>
        <Modal.Footer className='row justify-center'>
          <ButtonMaybePending
            variant={getButtonVariant(props.status)}
            isPending={isUpdatePending}
            type='submit'
            disabled={!isCollateralUpdateAllowed}>
            {getStatusText(props.status)}
          </ButtonMaybePending>
        </Modal.Footer>
      </form>
    </Modal>
  );
}
Example #24
Source File: request-replacement.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
export default function RequestReplacementModal(props: RequestReplacementProps): JSX.Element {
  const { register, handleSubmit, errors } = useForm<RequestReplacementForm>();
  const dispatch = useDispatch();
  const { address } = useSelector((state: StoreType) => state.general);
  const lockedDot = useSelector((state: StoreType) => state.vault.collateral);
  const lockedBtc = useSelector((state: StoreType) => state.vault.lockedBTC);
  const [isRequestPending, setRequestPending] = useState(false);
  const { t } = useTranslation();

  const onSubmit = handleSubmit(async ({ amount }) => {
    setRequestPending(true);
    try {
      if (btcToSat(amount.toString()) === undefined) {
        throw new Error('Amount to convert is less than 1 satoshi.');
      }
      const dustValue = await window.polkaBTC.redeem.getDustValue();
      const amountPolkaBtc = new Big(amount);
      if (amountPolkaBtc <= dustValue) {
        throw new Error(`Please enter an amount greater than Bitcoin dust (${dustValue.toString()} BTC)`);
      }
      await window.polkaBTC.replace.request(amountPolkaBtc);

      const vaultId = window.polkaBTC.api.createType(ACCOUNT_ID_TYPE_NAME, address);
      const requests = await window.polkaBTC.vaults.mapReplaceRequests(vaultId);
      if (!requests) return;

      dispatch(addReplaceRequestsAction(parachainToUIReplaceRequests(requests)));
      toast.success('Replacment request is submitted');
      props.onClose();
    } catch (error) {
      toast.error(error.toString());
    }
    setRequestPending(false);
  });

  return (
    <Modal
      show={props.show}
      onHide={props.onClose}>
      <form onSubmit={onSubmit}>
        <Modal.Header closeButton>
          <Modal.Title>{t('vault.request_replacement')}</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className='row'>
            <div className='col-12 request-header'>{t('vault.withdraw_your_collateral')}</div>
            <div className='col-12'>{t('vault.your_have')}</div>
            <div className='col-12'> {lockedDot} DOT</div>
            <div className='col-12 vault-empty-space'>
              {t('locked')} {lockedBtc} BTC
            </div>
            <div className='col-12 vault-empty-space'>{t('vault.replace_amount')}</div>
            <div className='col-12'>
              <div className='input-group'>
                <input
                  name='amount'
                  type='float'
                  className={'form-control custom-input' + (errors.amount ? ' error-borders' : '')}
                  aria-describedby='basic-addon2'
                  ref={register({
                    required: true
                  })}>
                </input>
                <div className='input-group-append'>
                  <span
                    className='input-group-text'
                    id='basic-addon2'>
                                        PolkaBTC
                  </span>
                </div>
                {errors.amount && (
                  <div className='input-error'>
                    {errors.amount.type === 'required' ?
                      'Amount is required' :
                      errors.amount.message}
                  </div>
                )}
              </div>
            </div>
          </div>
        </Modal.Body>
        <Modal.Footer>
          <Button
            variant='secondary'
            onClick={props.onClose}>
            {t('cancel')}
          </Button>
          <ButtonMaybePending
            variant='outline-danger'
            type='submit'
            isPending={isRequestPending}>
            {t('request')}
          </ButtonMaybePending>
        </Modal.Footer>
      </form>
    </Modal>
  );
}
Example #25
Source File: process-input.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
ProcessIdInput = (props: any) => {

    const { t } = useTranslation();
    const [processNo, setProcessNo] = React.useState('');
    const [btnOkDisabled, setBtnOkDisabled] = React.useState(false);
    const processIds = useGetPendingProcessIds(undefined, props.handleError);

    const handleCancel = () => {
        props.onCancel();
        // props.onHide();
    }

    const handleOk = () => {
        setBtnOkDisabled(true);
        props.onChange(processNo);
        // props.onHide();
    }

    const handleEnter = () => {
        setBtnOkDisabled(false);
    }

    return (
        <>
            <Modal
                contentClassName='data-modal'
                show={props.show}
                backdrop="static"
                keyboard={false}
                centered
                onEnter={handleEnter}
            >
                <Modal.Header id='data-header' className='pb-0' >
                    <Row>
                        <Col >
                            <Card.Title className='m-0 jcc-xs-jcfs-md' as={'h2'} >{t('translation:testId-input-header')}</Card.Title>
                        </Col>
                    </Row>
                </Modal.Header>

                {/*
    content area with process number input and radios
    */}
                <Modal.Body className='py-0 bg-light'>
                    <hr />

                    < FormGroupInput controlId='formProcessModalInput' title={t('translation:process-number')}
                        value={processNo}
                        onChange={(evt: any) => setProcessNo(evt.currentTarget.value)}
                        required
                        min={utils.shortHashLen}
                        maxLength={utils.shortHashLen}
                        pattern={utils.pattern.processNo}
                        datalistId='processId-list'
                        datalist={processIds ? processIds.map((i: IShortHashedGuid) => <option key={i.shortHashedGuid} value={i.shortHashedGuid} />) : undefined}
                    />

                    <hr />
                </Modal.Body>

                {/*
    footer with cancel and submit button
    */}
                <Modal.Footer id='data-footer'>
                    <Container className='p-0'>
                        <Row>
                            <Col xs='6' md='4' className='pl-0'>
                                <Button
                                    className='py-0'
                                    block
                                    variant='outline-primary'
                                    onClick={handleCancel}
                                >
                                    {t('translation:cancel')}
                                </Button>
                            </Col>
                            <Col xs='6' md='4' className='pr-0'>
                                <Button
                                    className='py-0'
                                    block
                                    onClick={handleOk}
                                    disabled={processNo.length !== utils.shortHashLen || btnOkDisabled}
                                >
                                    {t('translation:ok')}

                                    <Spinner
                                        as="span"
                                        className='btn-spinner'
                                        animation="border"
                                        hidden={!btnOkDisabled}
                                        size="sm"
                                        role="status"
                                        aria-hidden="true"
                                    />
                                </Button>
                            </Col>
                        </Row>
                    </Container>
                </Modal.Footer>
            </Modal>
        </>
    )
}
Example #26
Source File: redeem-modal.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
function RedeemModal(props: RedeemModalProps): ReactElement {
  const { address, prices } = useSelector((state: StoreType) => state.general);
  const selectedIdRequest = useSelector((state: StoreType) => state.redeem.id);
  const userRedeemRequests = useSelector((state: StoreType) => state.redeem.redeemRequests).get(address) || [];
  const request = userRedeemRequests.filter(request => request.id === selectedIdRequest)[0];
  const { t } = useTranslation();

  return (
    <Modal
      className='redeem-modal'
      show={props.show}
      onHide={props.onClose}
      size='xl'>
      {request && (
        <>
          <div className='redeem-modal-title'>{t('issue_page.request', { id: request.id })}</div>
          <i
            className='fas fa-times close-icon'
            onClick={props.onClose} />
          <div className='redeem-modal-horizontal-line' />
          <Modal.Body>
            <div className='row'>
              <div className='col-xl-6 col-lg-12 justify-center'>
                <div className='redeem-amount'>
                  <span className='wizard-number'>{request.amountPolkaBTC}</span>&nbsp;PolkaBTC
                </div>
                <div className='row usd-price-modal'>
                  <div className='col'>
                    {'~ $' + getUsdAmount(request.amountPolkaBTC || '0', prices.bitcoin.usd)}
                  </div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('bridge_fee')}</div>
                  <div className='col-6'>
                    <BitcoinLogoIcon
                      className='inline-block'
                      width={23}
                      height={23} />
                    {' '}
                    &nbsp;
                    {request.fee} BTC
                    <div className='send-price'>
                      {'~ $' + getUsdAmount(request.fee, prices.bitcoin.usd)}
                    </div>
                  </div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('bitcoin_network_fee')}</div>
                  <div className='col-6'>
                    <BitcoinLogoIcon
                      className='inline-block'
                      width={23}
                      height={23} />
                    {' '}
                    &nbsp;
                    {request.btcTransferFee} BTC
                    <div className='send-price'>
                      {'~ $' + getUsdAmount(request.btcTransferFee, prices.bitcoin.usd)}
                    </div>
                  </div>
                </div>
                <hr className='total-divider' />
                <div className='step-item row'>
                  <div className='col-6 total-amount temp-text-left total-added-value'>{t('you_will_receive')}</div>
                  <div className='col-6 total-amount'>
                    <BitcoinLogoIcon
                      className='inline-block'
                      width={23}
                      height={23} />
                      &nbsp;
                    {request.amountBTC} BTC
                    <div className='send-price'>
                      {'~ $' + getUsdAmount(request.amountBTC, prices.bitcoin.usd)}
                    </div>
                  </div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.destination_address')}</div>
                  <div className='col-6 right-text'>{shortAddress(request.userBTCAddress || '')}</div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.parachain_block')}</div>
                  <div className='col-6 right-text'>{request.creation}</div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.vault_dot_address')}</div>
                  <div className='col-6 right-text'>{shortAddress(request.vaultDOTAddress || '')}</div>
                </div>
              </div>
              <div className='col-xl-6 col-lg-12'>
                {request.status === RedeemRequestStatus.Expired ? (
                  <ReimburseView
                    request={request}
                    onClose={props.onClose} />
                ) : (
                  <StatusView request={request} />
                )}
              </div>
            </div>
          </Modal.Body>
        </>
      )}
    </Modal>
  );
}
Example #27
Source File: issue-modal.tsx    From polkabtc-ui with Apache License 2.0 4 votes vote down vote up
IssueModal = (props: IssueModalProps): JSX.Element => {
  const { address, prices } = useSelector((state: StoreType) => state.general);
  const selectedIdRequest = useSelector((state: StoreType) => state.issue.id);
  const userIssueRequests = useSelector((state: StoreType) => state.issue.issueRequests).get(address) || [];
  const request = userIssueRequests.filter(request => request.id === selectedIdRequest)[0];
  const { t } = useTranslation();

  const renderModalStatusPanel = (request: IssueRequest) => {
    switch (request.status) {
    case IssueRequestStatus.PendingWithBtcTxNotFound: {
      return <PaymentView request={request} />;
    }
    case IssueRequestStatus.RequestedRefund: {
      return <WhoopsView request={request} />;
    }
    default: {
      return <StatusView request={request} />;
    }
    }
  };

  return (
    <Modal
      className='issue-modal'
      show={props.open}
      onHide={props.onClose}
      size='xl'>
      {request && (
        <>
          <h4
            className={clsx(
              'break-words',
              'font-medium',
              'text-base',
              'text-interlayRose',
              'text-center',
              'uppercase'
            )}>
            {t('issue_page.request', { id: request.id })}
          </h4>
          {/* ray test touch < */}
          {/* TODO: could be a component */}
          <i
            className='fas fa-times close-icon'
            onClick={props.onClose} />
          {/* ray test touch > */}
          <div className='issue-modal-horizontal-line' />
          <Modal.Body>
            <div className='row'>
              <div className='col-xl-6 col-lg-12 justify-center'>
                <div className='issue-amount'>
                  <span className='wizard-number'>
                    {request.issuedAmountBtc || request.requestedAmountPolkaBTC}
                  </span>
                  &nbsp;PolkaBTC
                </div>
                <div className='row usd-price-modal'>
                  <div className='col'>
                    {'~ $' + getUsdAmount(
                      request.issuedAmountBtc || request.requestedAmountPolkaBTC || '0',
                      prices.bitcoin.usd
                    )}
                  </div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('bridge_fee')}</div>
                  <div className='col-6 right-text'>
                    <BitcoinLogoIcon
                      className='inline-block'
                      width={23}
                      height={23} />
                    {' '}
                    &nbsp;
                    {displayBtcAmount(request.fee)} BTC
                    <div className='send-price'>
                      {'~ $' + getUsdAmount(request.fee, prices.bitcoin.usd)}
                    </div>
                  </div>
                </div>
                <hr className='total-divider' />
                <div className='step-item row'>
                  <div className='col-6 total-added-value temp-text-left'>{t('total_deposit')}</div>
                  <div className='col-6 total-amount right-text'>
                    <BitcoinLogoIcon
                      className='inline-block'
                      width={23}
                      height={23} />
                    {' '}
                    &nbsp;
                    {displayBtcAmount(request.amountBTC)}
                    {' '}
                    BTC
                    <div className='send-price'>
                      {'~ $' + getUsdAmount(
                        request.issuedAmountBtc || request.requestedAmountPolkaBTC,
                        prices.bitcoin.usd
                      )}
                    </div>
                  </div>
                </div>
                {/* TODO: should be reusable */}
                <div className='step-item row mt-2'>
                  <div className='col-6 temp-text-left'>{t('issue_page.destination_address')}</div>
                  <div className='col-6 right-text'>{shortAddress(address)}</div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.parachain_block')}</div>
                  <div className='col-6 right-text'>{request.creation}</div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.vault_dot_address')}</div>
                  <div className='col-6 right-text'>{shortAddress(request.vaultDOTAddress)}</div>
                </div>
                <div className='step-item row'>
                  <div className='col-6 temp-text-left'>{t('issue_page.vault_btc_address')}</div>
                  <div className='col-6 right-text'>{shortAddress(request.vaultBTCAddress)}</div>
                </div>
                <div className='row justify-center mt-3'>
                  <div className='col-9 note-title'>{t('note')}:</div>
                </div>
                <div className='row justify-center'>
                  <div className='col-9 note-text'>{t('issue_page.fully_decentralized')}</div>
                </div>
              </div>
              <div className='col-xl-6 col-lg-12'>{renderModalStatusPanel(request)}</div>
            </div>
          </Modal.Body>
        </>
      )}
    </Modal>
  );
}
Example #28
Source File: UploadProgress.tsx    From bada-frame with GNU General Public License v3.0 4 votes vote down vote up
export default function UploadProgress(props: Props) {
    const appContext = useContext(AppContext);

    const fileProgressStatuses = [] as FileProgresses[];
    const fileUploadResultMap = new Map<FileUploadResults, number[]>();
    let filesNotUploaded = false;
    let sectionInfo = null;
    if (props.fileProgress) {
        for (const [localID, progress] of props.fileProgress) {
            fileProgressStatuses.push({
                fileID: localID,
                progress,
            });
        }
    }
    if (props.uploadResult) {
        for (const [localID, progress] of props.uploadResult) {
            if (!fileUploadResultMap.has(progress)) {
                fileUploadResultMap.set(progress, []);
            }
            if (
                progress !== FileUploadResults.UPLOADED &&
                progress !== FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL
            ) {
                filesNotUploaded = true;
            }
            const fileList = fileUploadResultMap.get(progress);

            fileUploadResultMap.set(progress, [...fileList, localID]);
        }
    }
    if (props.hasLivePhotos) {
        sectionInfo = constants.LIVE_PHOTOS_DETECTED();
    }

    function handleHideModal(): () => void {
        return props.uploadStage !== UPLOAD_STAGES.FINISH
            ? () => {
                  appContext.setDialogMessage({
                      title: constants.STOP_UPLOADS_HEADER,
                      content: constants.STOP_ALL_UPLOADS_MESSAGE,
                      proceed: {
                          text: constants.YES_STOP_UPLOADS,
                          variant: 'danger',
                          action: props.cancelUploads,
                      },
                      close: {
                          text: constants.NO,
                          variant: 'secondary',
                          action: () => {},
                      },
                  });
              }
            : props.closeModal;
    }

    return (
        <>
            <Modal
                show={props.show}
                aria-labelledby="contained-modal-title-vcenter"
                centered
                backdrop={fileProgressStatuses?.length !== 0 ? 'static' : true}>
                <Modal.Header
                    style={{
                        display: 'flex',
                        justifyContent: 'center',
                        textAlign: 'center',
                        borderBottom: 'none',
                        paddingTop: '30px',
                        paddingBottom: '0px',
                    }}>
                    <h4 style={{ width: '100%' }}>
                        {props.uploadStage === UPLOAD_STAGES.UPLOADING
                            ? constants.UPLOAD[props.uploadStage](
                                  props.fileCounter
                              )
                            : constants.UPLOAD[props.uploadStage]}
                    </h4>
                    <IoMdClose
                        size={30}
                        onClick={handleHideModal()}
                        style={{ cursor: 'pointer' }}
                    />
                </Modal.Header>
                <Modal.Body>
                    {(props.uploadStage ===
                        UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES ||
                        props.uploadStage ===
                            UPLOAD_STAGES.EXTRACTING_METADATA ||
                        props.uploadStage === UPLOAD_STAGES.UPLOADING) && (
                        <ProgressBar
                            now={props.now}
                            animated
                            variant="upload-progress-bar"
                        />
                    )}
                    {props.uploadStage === UPLOAD_STAGES.UPLOADING && (
                        <InProgressSection
                            filenames={props.filenames}
                            fileProgressStatuses={fileProgressStatuses}
                            sectionTitle={constants.INPROGRESS_UPLOADS}
                            sectionInfo={sectionInfo}
                        />
                    )}

                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.UPLOADED}
                        sectionTitle={constants.SUCCESSFUL_UPLOADS}
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={
                            FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL
                        }
                        sectionTitle={
                            constants.THUMBNAIL_GENERATION_FAILED_UPLOADS
                        }
                        sectionInfo={constants.THUMBNAIL_GENERATION_FAILED_INFO}
                    />

                    {props.uploadStage === UPLOAD_STAGES.FINISH &&
                        filesNotUploaded && (
                            <NotUploadSectionHeader>
                                {constants.FILE_NOT_UPLOADED_LIST}
                            </NotUploadSectionHeader>
                        )}

                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.BLOCKED}
                        sectionTitle={constants.BLOCKED_UPLOADS}
                        sectionInfo={constants.ETAGS_BLOCKED(
                            getOSSpecificDesktopAppDownloadLink()
                        )}
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.FAILED}
                        sectionTitle={constants.FAILED_UPLOADS}
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.ALREADY_UPLOADED}
                        sectionTitle={constants.SKIPPED_FILES}
                        sectionInfo={constants.SKIPPED_INFO}
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={
                            FileUploadResults.LARGER_THAN_AVAILABLE_STORAGE
                        }
                        sectionTitle={
                            constants.LARGER_THAN_AVAILABLE_STORAGE_UPLOADS
                        }
                        sectionInfo={
                            constants.LARGER_THAN_AVAILABLE_STORAGE_INFO
                        }
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.UNSUPPORTED}
                        sectionTitle={constants.UNSUPPORTED_FILES}
                        sectionInfo={constants.UNSUPPORTED_INFO}
                    />
                    <ResultSection
                        filenames={props.filenames}
                        fileUploadResultMap={fileUploadResultMap}
                        fileUploadResult={FileUploadResults.TOO_LARGE}
                        sectionTitle={constants.TOO_LARGE_UPLOADS}
                        sectionInfo={constants.TOO_LARGE_INFO}
                    />
                </Modal.Body>
                {props.uploadStage === UPLOAD_STAGES.FINISH && (
                    <Modal.Footer style={{ border: 'none' }}>
                        {props.uploadStage === UPLOAD_STAGES.FINISH &&
                            (fileUploadResultMap?.get(FileUploadResults.FAILED)
                                ?.length > 0 ||
                            fileUploadResultMap?.get(FileUploadResults.BLOCKED)
                                ?.length > 0 ? (
                                <Button
                                    variant="outline-success"
                                    style={{ width: '100%' }}
                                    onClick={props.retryFailed}>
                                    {constants.RETRY_FAILED}
                                </Button>
                            ) : (
                                <Button
                                    variant="outline-secondary"
                                    style={{ width: '100%' }}
                                    onClick={props.closeModal}>
                                    {constants.CLOSE}
                                </Button>
                            ))}
                    </Modal.Footer>
                )}
            </Modal>
        </>
    );
}
Example #29
Source File: PlanSelector.tsx    From bada-frame with GNU General Public License v3.0 4 votes vote down vote up
function PlanSelector(props: Props) {
    const subscription: Subscription = getUserSubscription();
    const [plans, setPlans] = useState<Plan[]>(null);
    const [planPeriod, setPlanPeriod] = useState<PLAN_PERIOD>(PLAN_PERIOD.YEAR);
    const galleryContext = useContext(GalleryContext);
    const appContext = useContext(AppContext);

    const togglePeriod = () => {
        setPlanPeriod((prevPeriod) =>
            prevPeriod === PLAN_PERIOD.MONTH
                ? PLAN_PERIOD.YEAR
                : PLAN_PERIOD.MONTH
        );
    };
    function onReopenClick() {
        appContext.closeMessageDialog();
        galleryContext.showPlanSelectorModal();
    }
    useEffect(() => {
        if (!props.modalView) {
            return;
        }
        const main = async () => {
            try {
                props.setLoading(true);
                let plans = await billingService.getPlans();

                const planNotListed =
                    plans.filter((plan) =>
                        isUserSubscribedPlan(plan, subscription)
                    ).length === 0;
                if (
                    subscription &&
                    !isOnFreePlan(subscription) &&
                    planNotListed
                ) {
                    plans = [planForSubscription(subscription), ...plans];
                }
                setPlans(plans);
            } catch (e) {
                logError(e, 'plan selector modal open failed');
                props.closeModal();
                props.setDialogMessage({
                    title: constants.OPEN_PLAN_SELECTOR_MODAL_FAILED,
                    content: constants.UNKNOWN_ERROR,
                    close: { text: 'close', variant: 'danger' },
                    proceed: {
                        text: constants.REOPEN_PLAN_SELECTOR_MODAL,
                        variant: 'success',
                        action: onReopenClick,
                    },
                });
            } finally {
                props.setLoading(false);
            }
        };
        main();
    }, [props.modalView]);

    async function onPlanSelect(plan: Plan) {
        if (
            hasMobileSubscription(subscription) &&
            !isSubscriptionCancelled(subscription)
        ) {
            props.setDialogMessage({
                title: constants.ERROR,
                content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE,
                close: { variant: 'danger' },
            });
        } else if (
            hasPaypalSubscription(subscription) &&
            !isSubscriptionCancelled(subscription)
        ) {
            props.setDialogMessage({
                title: constants.MANAGE_PLAN,
                content: constants.PAYPAL_MANAGE_NOT_SUPPORTED_MESSAGE(),
                close: { variant: 'danger' },
            });
        } else if (hasStripeSubscription(subscription)) {
            props.setDialogMessage({
                title: `${constants.CONFIRM} ${reverseString(
                    constants.UPDATE_SUBSCRIPTION
                )}`,
                content: constants.UPDATE_SUBSCRIPTION_MESSAGE,
                staticBackdrop: true,
                proceed: {
                    text: constants.UPDATE_SUBSCRIPTION,
                    action: updateSubscription.bind(
                        null,
                        plan,
                        props.setDialogMessage,
                        props.setLoading,
                        props.closeModal
                    ),
                    variant: 'success',
                },
                close: { text: constants.CANCEL },
            });
        } else {
            try {
                props.setLoading(true);
                await billingService.buySubscription(plan.stripeID);
            } catch (e) {
                props.setLoading(false);
                props.setDialogMessage({
                    title: constants.ERROR,
                    content: constants.SUBSCRIPTION_PURCHASE_FAILED,
                    close: { variant: 'danger' },
                });
            }
        }
    }

    const PlanIcons: JSX.Element[] = plans
        ?.filter((plan) => plan.period === planPeriod)
        ?.map((plan) => (
            <PlanIcon
                key={plan.stripeID}
                className="subscription-plan-selector"
                currentlySubscribed={isUserSubscribedPlan(plan, subscription)}
                onClick={
                    isUserSubscribedPlan(plan, subscription)
                        ? () => {}
                        : async () => await onPlanSelect(plan)
                }>
                <div>
                    <span
                        style={{
                            color: '#ECECEC',
                            fontWeight: 900,
                            fontSize: '40px',
                            lineHeight: '40px',
                        }}>
                        {convertBytesToGBs(plan.storage, 0)}
                    </span>
                    <span
                        style={{
                            color: '#858585',
                            fontSize: '24px',
                            fontWeight: 900,
                        }}>
                        {' '}
                        GB
                    </span>
                </div>
                <div
                    className="bold-text"
                    style={{
                        color: '#aaa',
                        lineHeight: '36px',
                        fontSize: '20px',
                    }}>
                    {`${plan.price} / ${plan.period}`}
                </div>
                <Button
                    variant="outline-success"
                    block
                    style={{
                        marginTop: '20px',
                        fontSize: '14px',
                        display: 'flex',
                        justifyContent: 'center',
                    }}
                    disabled={isUserSubscribedPlan(plan, subscription)}>
                    {constants.CHOOSE_PLAN_BTN}
                    <ArrowEast style={{ marginLeft: '5px' }} />
                </Button>
            </PlanIcon>
        ));
    return (
        <Modal
            show={props.modalView}
            onHide={props.closeModal}
            size="xl"
            centered
            backdrop={hasPaidSubscription(subscription) ? true : 'static'}
            contentClassName="plan-selector-modal-content">
            <Modal.Header closeButton>
                <Modal.Title
                    style={{
                        marginLeft: '12px',
                        width: '100%',
                        textAlign: 'center',
                    }}>
                    <span>
                        {hasPaidSubscription(subscription)
                            ? constants.MANAGE_PLAN
                            : constants.CHOOSE_PLAN}
                    </span>
                </Modal.Title>
            </Modal.Header>
            <Modal.Body style={{ marginTop: '20px' }}>
                <DeadCenter>
                    <div style={{ display: 'flex' }}>
                        <span
                            className="bold-text"
                            style={{ fontSize: '16px' }}>
                            {constants.MONTHLY}
                        </span>

                        <Form.Switch
                            checked={planPeriod === PLAN_PERIOD.YEAR}
                            id="plan-period-toggler"
                            style={{
                                margin: '-4px 0 20px 15px',
                                fontSize: '10px',
                            }}
                            className="custom-switch-md"
                            onChange={togglePeriod}
                        />
                        <span
                            className="bold-text"
                            style={{ fontSize: '16px' }}>
                            {constants.YEARLY}
                        </span>
                    </div>
                </DeadCenter>
                <div
                    style={{
                        display: 'flex',
                        justifyContent: 'space-around',
                        flexWrap: 'wrap',
                        minHeight: '212px',
                        margin: '5px 0',
                    }}>
                    {plans && PlanIcons}
                </div>
                <DeadCenter style={{ marginBottom: '30px' }}>
                    {hasPaidSubscription(subscription) ? (
                        <>
                            {hasStripeSubscription(subscription) && (
                                <>
                                    {isSubscriptionCancelled(subscription) ? (
                                        <LinkButton
                                            variant="success"
                                            onClick={() =>
                                                props.setDialogMessage({
                                                    title: constants.CONFIRM_ACTIVATE_SUBSCRIPTION,
                                                    content:
                                                        constants.ACTIVATE_SUBSCRIPTION_MESSAGE(
                                                            subscription.expiryTime
                                                        ),
                                                    staticBackdrop: true,
                                                    proceed: {
                                                        text: constants.ACTIVATE_SUBSCRIPTION,
                                                        action: activateSubscription.bind(
                                                            null,
                                                            props.setDialogMessage,
                                                            props.closeModal,
                                                            props.setLoading
                                                        ),
                                                        variant: 'success',
                                                    },
                                                    close: {
                                                        text: constants.CANCEL,
                                                    },
                                                })
                                            }>
                                            {constants.ACTIVATE_SUBSCRIPTION}
                                        </LinkButton>
                                    ) : (
                                        <LinkButton
                                            variant="danger"
                                            onClick={() =>
                                                props.setDialogMessage({
                                                    title: constants.CONFIRM_CANCEL_SUBSCRIPTION,
                                                    content:
                                                        constants.CANCEL_SUBSCRIPTION_MESSAGE(),
                                                    staticBackdrop: true,
                                                    proceed: {
                                                        text: constants.CANCEL_SUBSCRIPTION,
                                                        action: cancelSubscription.bind(
                                                            null,
                                                            props.setDialogMessage,
                                                            props.closeModal,
                                                            props.setLoading
                                                        ),
                                                        variant: 'danger',
                                                    },
                                                    close: {
                                                        text: constants.CANCEL,
                                                    },
                                                })
                                            }>
                                            {constants.CANCEL_SUBSCRIPTION}
                                        </LinkButton>
                                    )}
                                    <LinkButton
                                        variant="primary"
                                        onClick={updatePaymentMethod.bind(
                                            null,
                                            props.setDialogMessage,
                                            props.setLoading
                                        )}
                                        style={{ marginTop: '20px' }}>
                                        {constants.MANAGEMENT_PORTAL}
                                    </LinkButton>
                                </>
                            )}
                            <LinkButton
                                variant="primary"
                                onClick={manageFamilyMethod.bind(
                                    null,
                                    props.setDialogMessage,
                                    props.setLoading
                                )}
                                style={{ marginTop: '20px' }}>
                                {constants.MANAGE_FAMILY_PORTAL}
                            </LinkButton>
                        </>
                    ) : (
                        <LinkButton
                            variant="primary"
                            onClick={props.closeModal}
                            style={{
                                color: 'rgb(121, 121, 121)',
                                marginTop: '20px',
                            }}>
                            {isOnFreePlan(subscription)
                                ? constants.SKIP
                                : constants.CLOSE}
                        </LinkButton>
                    )}
                </DeadCenter>
            </Modal.Body>
        </Modal>
    );
}