react-bootstrap#Collapse TypeScript Examples

The following examples show how to use react-bootstrap#Collapse. 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: AccContractCard.tsx    From devex with GNU General Public License v3.0 6 votes vote down vote up
AccContractCard: React.FC<IProps> = ({ contract, index }) => {

  const [showContractState, setShowContractState] = useState<boolean>(false)

  return <Card className='acc-contract-card'>
    <Card.Body onClick={() => { setShowContractState((prevState) => !prevState) }} key={index}>
      <div>
        <span className='mono'>
          {`${index + 1}) `}
          {<QueryPreservingLink onClick={(e: React.MouseEvent<HTMLAnchorElement>) => { e.stopPropagation() }}
            to={`/address/${hexAddrToZilAddr(contract.address)}`}>
            {hexAddrToZilAddr(contract.address)}
          </QueryPreservingLink>}
        </span>
        <span>
          <FontAwesomeIcon icon={showContractState ? faChevronUp : faChevronDown} />
        </span>
      </div>
    </Card.Body>
    <Collapse in={showContractState}>
      <div>
        <pre className='display-block'>
          {JSON.stringify(contract.state, null, 2)}
        </pre>
      </div>
    </Collapse>
  </Card>
}
Example #2
Source File: FilterItemComponent.tsx    From rcsb-saguaro-app with MIT License 5 votes vote down vote up
render():JSX.Element {
        return (<>
            <ItemComponent onClick={()=>this.setState({collapseIn:!this.state.collapseIn})} >FILTER</ItemComponent>
            <Collapse in={this.state.collapseIn}>
                <div className={"position-absolute"} ></div>
            </Collapse>
        </>);
    }
Example #3
Source File: DSBlockDetailsPage.tsx    From devex with GNU General Public License v3.0 4 votes vote down vote up
DSBlockDetailsPage: React.FC = () => {

  const { blockNum } = useParams()
  const networkContext = useContext(NetworkContext)
  const { dataService } = networkContext!

  const [isLoading, setIsLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [data, setData] = useState<DsBlockObj | null>(null)
  const [latestDSBlockNum, setLatestDSBlockNum] = useState<number | null>(null)
  const [minerInfo, setMinerInfo] = useState<MinerInfo | null>(null)
  const [currShardIdx, setCurrShardIdx] = useState<number>(0)
  const [showMore, setShowMore] = useState<boolean>(false)

  // Fetch data
  useEffect(() => {
    setIsLoading(true)
    if (!dataService) return
    
    let latestDSBlockNum: number
    let receivedData: DsBlockObj
    let minerInfo: MinerInfo
    const getData = async () => {
      try {
        if (isNaN(blockNum))
          throw new Error('Not a valid block number')
        receivedData = await dataService.getDSBlockDetails(blockNum)
        latestDSBlockNum = await dataService.getNumDSBlocks()
        try { // wrapped in another try catch because it is optional
          minerInfo = await dataService.getMinerInfo(blockNum)
        } catch (e) { console.log(e) }
        if (receivedData)
          setData(receivedData)
        if (latestDSBlockNum)
          setLatestDSBlockNum(latestDSBlockNum)
        if (minerInfo)
          setMinerInfo(minerInfo)
      } catch (e) {
        console.log(e)
        setError(e)
      } finally {
        setIsLoading(false)
      }
    }

    getData()
    return () => {
      setData(null)
      setLatestDSBlockNum(null)
      setMinerInfo(null)
      setError(null)
      setCurrShardIdx(0)
      setShowMore(false)
    }
  }, [blockNum, dataService])

  return <>
    {isLoading ? <div className='center-spinner'><Spinner animation="border" /></div> : null}
    {error
      ? <NotFoundPage />
      : data && (
        <>
          <div className='dsblock-header'>
            <h3 className='mb-1'>
              <span className='mr-1'>
                <FontAwesomeIcon className='fa-icon' icon={faCubes} />
              </span>
              <span className='ml-2'>
                DS Block
              </span>
              {' '}
              <span className='subtext'>#{data.header.BlockNum}</span>
              <LabelStar type='DS Block' />
            </h3>
            <span>
              <QueryPreservingLink
                className={parseInt(data.header.BlockNum) === 0
                  ? 'disabled mr-3' : 'mr-3'}
                to={`/dsbk/${parseInt(data.header.BlockNum) - 1}`}>
                <FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareLeft} />
              </QueryPreservingLink>
              <QueryPreservingLink
                className={latestDSBlockNum && parseInt(data.header.BlockNum) === latestDSBlockNum - 1 ? 'disabled' : ''}
                to={`/dsbk/${parseInt(data.header.BlockNum) + 1}`}>
                <FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareRight} />
              </QueryPreservingLink>
            </span>
          </div>
          <Card className='dsblock-details-card'>
            <Card.Body>
              <Container>
                <Row>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>Date:</span>
                      <span>
                        {timestampToDisplay(data.header.Timestamp)}
                        {' '}
                        ({timestampToTimeago(data.header.Timestamp)})
                    </span>
                    </div>
                  </Col>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>Difficulty:</span>
                      <span>{data.header.Difficulty}</span>
                    </div>
                  </Col>
                </Row>
                <Row>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>DS Difficulty:</span>
                      <span>{data.header.DifficultyDS}</span>
                    </div>
                  </Col>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>Gas Price:</span>
                      <span>{qaToZil(data.header.GasPrice)}</span>
                    </div>
                  </Col>
                </Row>
                <Row>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>DS Leader:</span>
                      <span>
                        <QueryPreservingLink to={`/address/${pubKeyToZilAddr(data.header.LeaderPubKey)}`}>
                          {pubKeyToZilAddr(data.header.LeaderPubKey)}
                        </QueryPreservingLink>
                      </span>
                    </div>
                  </Col>
                </Row>
                <Row>
                  <Col>
                    <div className='dsblock-detail'>
                      <span>Signature:</span>
                      <span className='dsblock-signature'>{data.signature}</span>
                    </div>
                  </Col>
                </Row>
              </Container>
            </Card.Body>
          </Card>
          {data.header.PoWWinners.length > 0 && (
            <Card className='dsblock-details-card'>
              <Card.Body>
                <Container className='mono'>
                  <h6 className='mb-2'>PoW Winners</h6>
                  {data.header.PoWWinners.map((x, index) => <div key={index}>[{index}]
                    {'  '}
                    <QueryPreservingLink to={`/address/${pubKeyToZilAddr(x)}`}>{pubKeyToZilAddr(x)}</QueryPreservingLink></div>)}
                </Container>
              </Card.Body>
            </Card>
          )}
          {minerInfo &&
            <>
              <Collapse in={showMore}>
                <Row>
                  <Col>
                    <Card className='miner-card'>
                      <Card.Body>
                        <Container className='mono'>
                          <Row className='justify-content-between'>
                            <span>DS Committee</span>
                            <span>Total: <strong>{minerInfo.dscommittee.length}</strong></span>
                          </Row>
                          <Row className='justify-content-center'>
                            {minerInfo.dscommittee.length > 0
                              ? <MinerTable addresses={minerInfo.dscommittee} />
                              : <span className='my-3'>No addresses to show</span>
                            }
                          </Row>
                        </Container>
                      </Card.Body>
                    </Card>
                  </Col>
                  <Col>
                    <Card className='miner-card ml-auto'>
                      <Card.Body>
                        <Container className='mono'>
                          <Row className='justify-content-between'>
                            <Col>
                              <span>Shard {currShardIdx + 1} of {minerInfo.shards.length}</span>
                            </Col>
                            <Col className='text-center shard-toggle'>
                              <span>
                                <FontAwesomeIcon size='2x'
                                  cursor='pointer'
                                  onClick={currShardIdx === 0 ? undefined : () => (setCurrShardIdx(currShardIdx - 1))}
                                  className={currShardIdx === 0 ? 'disabled' : ''} icon={faAngleLeft} />
                                <FontAwesomeIcon size='2x'
                                  cursor='pointer'
                                  onClick={currShardIdx === minerInfo.shards.length - 1 ? undefined : () => (setCurrShardIdx(currShardIdx + 1))}
                                  className={currShardIdx === minerInfo.shards.length - 1 ? 'disabled ml-3' : 'ml-3'} icon={faAngleRight} />
                              </span>
                            </Col>
                            <Col className='text-right'>
                              <span>
                                Total:
                                {' '}
                                <strong>{minerInfo.shards[currShardIdx].nodes.length}</strong>
                              </span>
                            </Col>
                          </Row>
                          <Row className='justify-content-center'>
                            {minerInfo.shards[currShardIdx].nodes.length > 0
                              ? <MinerTable addresses={minerInfo.shards[currShardIdx].nodes} />
                              : <span className='my-3'>No addresses to show</span>
                            }
                          </Row>
                        </Container>
                      </Card.Body>
                    </Card>
                  </Col>
                </Row>
              </Collapse>
            </>
          }
          <Container className='showmore-container' onClick={() => setShowMore(!showMore)}>
            <Row>
              <FontAwesomeIcon icon={showMore ? faAngleUp : faAngleDown} size='2x' className='fa-icon' />
            </Row>
          </Container>
        </>
      )}
  </>
}
Example #4
Source File: group-modal.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
GroupModal = (props: any) => {

    const [btnOkDisabled, setBtnOkDisabled] = React.useState(true);
    const { t } = useTranslation();
    const { keycloak } = useKeycloak();

    const [data, setData] = React.useState('');
    const [validated, setValidated] = React.useState(false);
    const [isReady, setIsReady] = React.useState(false);
    const [isNew, setIsNew] = React.useState(true);
    const [options, setOptions] = React.useState<JSX.Element[]>();
    const [dropdownItems, setDropdownItems] = React.useState<JSX.Element[]>();
    const [dropdownList] = React.useState<string[]>(['https://', 'http://']);
    const [selectedDropdownValue, setSelectedDropdownValue] = React.useState<string>(dropdownList[0]);
    const [websiteValue, setWebsiteValue] = React.useState('');
    const [displayOpeningHours, setDisplayOpeningHours] = React.useState('');
    const [errorOpeningHour, setErrorOpeningHour] = React.useState('');

    const groupReloaded = (group: IGroupDetails) => {
        if (group) {
            setData(unpackData(group.pocDetails))
            group.parentGroup = props.parentGroupId;

            if (group.website) {
                let website = '';

                for (const item of dropdownList) {
                    if (group.website.startsWith(item)) {
                        website = group.website.slice(item.length, group.website.length);
                        setSelectedDropdownValue(item);
                    }
                }

                setWebsiteValue(website);
            }
            else {
                setWebsiteValue('');
                setSelectedDropdownValue(dropdownList[0]);
            }
        }
        setBtnOkDisabled(false);
    }

    const [group, updateGroup, setGroup] = useGetGroupDetails(groupReloaded, props.handleError);


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

    React.useEffect(() => {
        if (group) {

            setOptions(getOptions());
            setDisplayOpeningHours(
                group.openingHours?.map(
                    (element: string) => element)
                    .join('\n')
            );

            setIsReady(true);
        }

        setIsNew(!(group && group.id));
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [group])

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

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

    const handleCancel = () => {
        setErrorOpeningHour('');
        props.onCancel();
    }

    const unpackData = (data: string) => {
        if (data) {
            data = data.replaceAll(',', '\n')
        } else {
            data = ''
        }
        return data;
    }

    const packData = (data: string) => {
        if (data) {
            data = data.replaceAll('\n', ',')
        }
        return data;
    }

    const handleOk = () => {
        if (props.handleOk) {
            setBtnOkDisabled(true);
            group.pocDetails = packData(data);
            if (websiteValue
                && (
                    websiteValue.startsWith('www.')
                    || !(
                        websiteValue.startsWith(dropdownList[0])
                        || websiteValue.startsWith(dropdownList[1])
                    )
                )) {
                group.website = selectedDropdownValue + websiteValue;
            }
            else {
                group.website = websiteValue;
            }

            props.handleOk(group);
        }
    }

    const handleEnter = () => {
        if (props.onEnter) {
            props.onEnter();
        }

        setBtnOkDisabled(false);

        if (props.groupId) {
            updateGroup(props.groupId);
        }
        else {
            setGroup({ ...emptyGroup });
            setSelectedDropdownValue(dropdownList[0]);
            setData('');
            setWebsiteValue('');
        }
    }

    const handleExited = () => {
        setIsReady(false);
        props.onExit();
    }

    const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
        const form = event.currentTarget;
        event.preventDefault();
        event.stopPropagation();

        if (errorOpeningHour) {
            document.getElementById('formPocOpeningHours')?.focus();
            return;
        }

        if (form.checkValidity()) {
            handleOk();
        }
    }

    const updateGroupProp = (name: string, value: any) => {
        const ngroup = { ...group, [name]: value };
        setGroup({ ...ngroup });
    }

    const changeOpeningHoursHandler = (name: string, value: string) => {

        setDisplayOpeningHours(value);

        let error = undefined;
        const openingHours = value.split('\n');
        if (openingHours.length > 7) {
            setErrorOpeningHour('opening-hours-to-much-lines-error');
            return;
        }

        error = openingHours.find(element => {
            return !utils.isOpeningHoursValid(element);
        });

        if (error) {
            setErrorOpeningHour('openening-hours-to-long-error');
        } else {
            setErrorOpeningHour('');
            updateGroupProp("openingHours", openingHours);
        }
    }

    const updateSearchPortalConsent = (name: string, value: any) => {
        const ngroup: IGroupDetails = { ...group, [name]: value };

        if (value === false) {
            ngroup.email = '';
            ngroup.website = '';
            ngroup.openingHours = [];
            ngroup.appointmentRequired = false;
        }
        setGroup(ngroup);
    }

    const collectChildren = (idlist: string[], parentNode: IGroup) => {
        if (parentNode) {
            idlist.push(parentNode.id);
            parentNode.children.forEach(child => collectChildren(idlist, child as IGroup));
        }
    }

    const getOptions = (): JSX.Element[] => {
        let result: JSX.Element[] = [];

        if (group && group.id) {

            const node = props.groups.find((groupNode: IGroupNode) => groupNode.group.id === group.id);
            const selfIdOrChildren: string[] = [];

            if (node) {
                collectChildren(selfIdOrChildren, node.group);
            }

            const fList = props.groups.filter((groupNode: IGroupNode) => selfIdOrChildren.indexOf(groupNode.group.id) < 0)

            result = fList.map((groupNode: IGroupNode) =>
                <option key={groupNode.group.id} value={groupNode.group.id}>{"\u00A0\u00A0\u00A0\u00A0".repeat(groupNode.level) + groupNode.group.name}</option>
            );

            // result.push(<option key="empty" value="empty">{t('translation:no-parentgroup-option')}</option>);
        }


        return result;
    }

    const getDropdownItems = () => {
        setDropdownItems(
            dropdownList.map(
                (item: string) =>
                    <Dropdown.Item
                        onSelect={(eventKey: any) => setSelectedDropdownValue(eventKey)}
                        eventKey={item}
                        key={item}
                    >
                        {item}
                    </Dropdown.Item>));
    }

    return (
        <Modal
            contentClassName='data-modal'
            size="lg"
            show={props.show}
            backdrop="static"
            keyboard={false}
            centered
            onEnter={handleEnter}
            onExited={handleExited}
        >
            {!isReady
                ? <CwaSpinner background='#eeeeee' />
                : <Fade appear={true} in={true} >
                    <Form
                        className='form-flex'
                        onSubmit={handleSubmit}
                        validated={validated}
                    >
                        <Modal.Header id='data-header' className='pb-0' >
                            <Modal.Title>{isNew ? t('translation:add-group') : t('translation:edit-group')}</Modal.Title>
                        </Modal.Header>

                        <Modal.Body className='bg-light'>
                            {isNew
                                ? <></>
                                : <>
                                    <FormGroupSelect controlId='formGroupSelect'
                                        title={t('translation:parentgroup')}
                                        placeholder={t('translation:no-parentgroup-option')}
                                        value={group.parentGroup}
                                        onChange={(ent: any) => updateGroupProp('parentGroup', ent.target.value)}
                                        options={options}
                                    />

                                    <hr />
                                </>
                            }

                            < FormGroupInput controlId='formFirstName' title={t('translation:name')}
                                value={group ? group.name : ''}
                                required
                                onChange={(evt: any) => {
                                    updateGroupProp('name', evt.target.value);
                                    props.resetError();
                                }}
                                maxLength={45}
                                isInvalid={props.isCreationError}
                                InvalidText={t('translation:group-conflict-error')}
                            />

                            {/* <hr /> */}

                            < FormGroupTextarea controlId='formAdressData' title={t('translation:address-testcenter')} placeholder={t('translation:address-testcenter-placeholder')}
                                value={data}
                                required
                                onChange={(evt: any) => setData(evt.target.value)}
                                type='textarea'
                                maxLength={300}
                            />

                            {utils.hasRole(keycloak, 'c19_quick_test_poc_nat_admin')
                                ?
                                <FormGroupPermissionCkb controlId='formenablePcr' title={t('translation:enablePcr')}
                                    //label={t('translation:for-counter')}
                                    onChange={(evt: any) => updateSearchPortalConsent('enablePcr', evt.currentTarget.checked)}
                                    type='checkbox'
                                    checked={group.enablePcr}
                                />
                                : <></>
                            }

                            <hr />

                            {/* < FormGroupInput controlId='formBSNRInput' title={t('translation:bsnr')} placeholder={t('translation:bsnr-placeholder')}
                                value={group ? group.bsnr : ''}
                                onChange={(evt: any) => {
                                    updateGroupProp('bsnr', evt.target.value);
                                    props.resetError();
                                }}
                                maxLength={9}
                                prepend='i'
                                tooltip={t('translation:bsnr-tooltip')}
                                pattern={utils.pattern.BSNR}
                            /> */}

                            <FormGroupPermissionCkb controlId='formsearchPortalConsent' title={t('translation:searchPortalConsent')}
                                //label={t('translation:for-counter')}
                                onChange={(evt: any) => updateSearchPortalConsent('searchPortalConsent', evt.currentTarget.checked)}
                                type='checkbox'
                                checked={group.searchPortalConsent}
                            />

                            <Collapse in={group.searchPortalConsent}>
                                <div>
                                    < FormGroupInput controlId='formEmailInput' title={t('translation:email-address')}
                                        value={group?.email ? group.email : ''}
                                        onChange={(evt: any) => {
                                            updateGroupProp('email', evt.target.value);
                                            props.resetError();
                                        }}
                                        type='email'
                                        pattern={utils.pattern.eMail}
                                        minLength={5}
                                        maxLength={255}
                                    />
                                    < FormGroupInput controlId='formPocWebsite' title={t('translation:searchPortalWebsite')} placeholder={t('translation:searchPortalWebsitePlaceholder')}
                                        value={websiteValue}
                                        dropdown={dropdownItems}
                                        dropdownTitle={selectedDropdownValue}
                                        prepend='i'
                                        tooltip={t('translation:searchPortalWebsiteTooltip')}
                                        onChange={(evt: any) => {
                                            setWebsiteValue(evt.target.value);
                                            props.resetError();
                                        }}
                                        maxLength={100}
                                        pattern={utils.pattern.url}
                                    />

                                    < FormGroupTextarea controlId='formPocOpeningHours' title={t('translation:searchPortalOpeningHours')}
                                        value={displayOpeningHours}
                                        onChange={(evt: any) => {
                                            changeOpeningHoursHandler('openingHours', evt.target.value);
                                            props.resetError();
                                        }}
                                        type='textarea'
                                        rows={7}
                                        pattern={utils.pattern.email}
                                        isInvalid={errorOpeningHour}
                                        invalidText={errorOpeningHour && t('translation:' + errorOpeningHour)}
                                    />
                                    <FormGroupPermissionCkb controlId='formAppointmentRequired' title={t('translation:searchPortalAppointmentRequired')}
                                        onChange={(evt: any) => updateGroupProp('appointmentRequired', evt.currentTarget.checked)}
                                        type='checkbox'
                                        checked={group?.appointmentRequired ? group.appointmentRequired : false}
                                    />
                                </div>
                            </Collapse>

                            {!(group && group.pocId)
                                ? <></>
                                : <>
                                    <hr />
                                    < FormGroupInput controlId='formPocId' title={t('translation:poc-id')}
                                        value={group && group.pocId ? group.pocId : ''}
                                        readOnly
                                    />
                                </>
                            }

                        </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={handleCancel}
                                        >
                                            {t('translation:cancel')}
                                        </Button>
                                    </Col>
                                    <Col sm='6' lg='4' className='p-0 pl-sm-2'>
                                        <Button
                                            className='p-0'
                                            block
                                            type='submit'
                                            disabled={btnOkDisabled}
                                        >
                                            {isNew ? t('translation:add') : t('translation:edit')}

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

    // const context = React.useContext(AppContext);

    const { t } = useTranslation();
    const { keycloak } = useKeycloak();

    const handleSuccess = () => {
        setIsGroupCreationError(false);
        setIsGroupSuccessfullUpdated(true);
        setTimeout(setIsGroupEdit, 300, false);
        setShowConfirm(false);
    }

    const [isGroupEdit, setIsGroupEdit] = React.useState(false);
    const [editGroupId, setEditGroupId] = React.useState<string>('');
    const [editGroupParentId, setEditGroupParentId] = React.useState<string>('');
    const [showConfirm, setShowConfirm] = React.useState(false);
    const [isGroupSuccessfullUpdated, setIsGroupSuccessfullUpdated] = React.useState(false);
    const [isGroupCreationError, setIsGroupCreationError] = React.useState(false);
    const [confirmMessage, setConfirmMessage] = React.useState('');
    const [confirmTitle, setConfirmTitle] = React.useState('');
    const [confirmHandle, setConfirmHandle] = React.useState<() => void>();
    const [groupIsReady, setGroupIsReady] = React.useState(false);

    const [
        bGroups,
        refreshGroups,
        createGroup,
        updateGroup,
        deleteGroup
    ] = useGetGroups(() => setGroupIsReady(true), props.handleError);


    React.useEffect(() => {
        if (bGroups) {
            const _groupNodes: IGroupNode[] = [];
            flattenGroups(bGroups, _groupNodes, 0);
            props.setGroupNodes(_groupNodes);
        }
        else {
            props.setGroupNodes([]);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [bGroups]);

    const flattenGroups = (groups: IGroup[], groupNodes: IGroupNode[], level: number, parentGroup?: string): void => {
        groups.forEach((group: IGroup) => {

            const gNode: IGroupNode = {
                group: group,
                parentGroup: parentGroup,
                level: level,
            };

            groupNodes.push(gNode);

            if (group.children) {
                flattenGroups(group.children, groupNodes, level + 1, group.id);
            }
        });
    }

    const groupUpdate = (group: IGroupDetails) => {
        if (group.id) {

            if (keycloak.token) {

                const uGroup: any = { ...group };
                delete uGroup.parentGroup;

                updateGroup(uGroup)
                    .then(() => {
                        const fgroupNode = props.groupNodes.find((groupNode: IGroupNode) => groupNode.group.id === group.id);

                        if (keycloak.token
                            && fgroupNode
                            && group.id
                            && group.parentGroup
                            && fgroupNode.parentGroup !== group.parentGroup) {
                            addGroupAsChild(group.id, group.parentGroup, keycloak.token)
                                .then(() => {
                                    refreshGroups(() => { handleSuccess(); props.setUserReload(true); });
                                })
                                .catch(e => {
                                    props.handleError(e);
                                });
                        } else {
                            refreshGroups(() => { handleSuccess(); props.setUserReload(true); });
                        }
                    })
                    .catch(e => {
                        if (e && e.message && (e.message as string).includes('409')) {
                            setIsGroupCreationError(true);
                        }
                        else {
                            props.handleError(e);
                        }
                    })
            }
        } else {
            createGroup(group)
                .then(() => {
                    refreshGroups(handleSuccess);
                })
                .catch(e => {
                    if (e && e.message && (e.message as string).includes('409')) {
                        setIsGroupCreationError(true);
                    }
                    else {
                        props.handleError(e);
                    }
                })
        }

        // setIsGroupEdit(false);
    }

    const startEditGroup = (groupNode: IGroupNode) => {
        setEditGroupId(groupNode.group.id);
        setEditGroupParentId(groupNode.parentGroup ? groupNode.parentGroup : '');
        setIsGroupEdit(true);
    }

    const handleDeleteGroup = (group: IGroup) => {
        setConfirmTitle(t('translation:delete-group-title', { groupName: group.name }));
        setConfirmMessage(t('translation:delete-group-msg'));
        setShowConfirm(true);

        const handle = () => {
            if (keycloak.token && group.id) {
                deleteGroup(group.id)
                    .then(() => {
                        refreshGroups(() => { handleSuccess(); props.setUserReload(true); });

                    })
                    .catch(e => {
                        if (e && e.message && (e.message as string).includes('412')) {
                            setShowConfirm(false);
                            props.handleError(e, t('translation:delete-group-error'), () => { });
                        }
                        else {
                            props.handleError(e);
                        }
                    })
            }
        };
        // need to wrap a function again because react apply each function passed to hook
        setConfirmHandle(() => handle);
    }

    return (<>
        {
            !(props.groupNodes && groupIsReady)
                ? <CwaSpinner background='#eeeeee' />
                : <Collapse appear={true} in={true}>
                    <Container className='p-0 '>
                        <Table bordered hover>
                            <thead>
                                <tr>
                                    <th>{t('translation:name')}</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>{
                                props.groupNodes.map((g: IGroupNode, i: number) =>
                                    <tr key={i}>
                                        <td width="90%">{utils.getIndent(g.level)}{g.group.name}</td>
                                        <td className='td-btn'>
                                            <Row className='m-0 justify-content-around'>
                                                <Button
                                                    className="btn-icon edit-icon"
                                                    onClick={() => startEditGroup(g)}
                                                >
                                                </Button>
                                                <Button className="btn-icon delete-icon"
                                                    onClick={() => handleDeleteGroup(g.group)}
                                                />
                                            </Row>
                                        </td>
                                    </tr>
                                )
                            }
                            </tbody>
                        </Table>

                        <Button
                            className='btn-add'
                            size="sm"
                            variant="light"
                            onClick={() => { setEditGroupId(''); setIsGroupEdit(true) }}
                        >
                            <img className='mr-2' src={imageAdd} alt="Hinzufügen" />
                            {t('translation:add-group')}
                        </Button>
                    </Container>
                </Collapse>
        }

        <GroupModal
            show={isGroupEdit}
            groupId={editGroupId}
            parentGroupId={editGroupParentId}
            handleOk={groupUpdate}
            groups={props.groupNodes}
            isSuccess={isGroupSuccessfullUpdated}
            isCreationError={isGroupCreationError}
            onEnter={() => setIsGroupSuccessfullUpdated(false)}
            resetError={() => setIsGroupCreationError(false)}
            handleError={
                (err: any) => {
                    setIsGroupEdit(false);
                    props.handleError(err);
                }
            }
            onCancel={
                () => { setIsGroupEdit(false); }
            }
            onExit={
                () => {
                    setIsGroupSuccessfullUpdated(false);
                    setIsGroupCreationError(false);
                }
            }
        />
        <ConfirmModal
            show={showConfirm}
            title={confirmTitle}
            message={confirmMessage}
            onCancel={() => {
                setConfirmHandle(undefined);
                setShowConfirm(false);
            }}
            handleOk={() => {
                if (confirmHandle) {
                    confirmHandle();
                }
            }}
        />
    </>
    )

}
Example #6
Source File: person-data-inputs.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
PersonInputs = (props: any) => {
  const { t } = useTranslation();
  const [givenNameTransliteration, givenNameTransliterationUpdate] =
    useTransliterate();
  const [familyNameTransliteration, familyNameTransliterationUpdate] =
    useTransliterate();

  const [givenName, setGivenName] = React.useState<string>('');
  const [familyName, setFamilyName] = React.useState<string>('');

  const [standardisedGivenName, setStandardisedGivenName] =
    React.useState<string>('');
  const [standardisedFamilyName, setStandardisedFamilyName] =
    React.useState<string>('');

  const [dateOfBirth, setDateOfBirth] = React.useState<Date>();
  const [sex, setSex] = React.useState<Sex>();

  React.useEffect(() => {
    if (props && props.quickTest && props.quickTest.personData) {
      const personData = props.quickTest.personData;

      if (personData.givenName) {
        handleGivenNameChanged(personData.givenName);
      }
      if (personData.standardisedGivenName) {
        setStandardisedGivenName(personData.standardisedGivenName);
      }
      if (personData.familyName) {
        handleFamilyNameChanged(personData.familyName);
      }
      setStandardisedFamilyName(personData.standardisedFamilyName);

      if (personData.dateOfBirth) {
        setDateOfBirth(new Date(personData.dateOfBirth));
      }

      if (personData.sex) {
        setSex(personData.sex);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  React.useEffect(() => {
    const result: IPersonData = {
      givenName: givenName,
      familyName: familyName,
      standardisedGivenName: props.dccConsent
        ? standardisedGivenName
        : undefined,
      standardisedFamilyName: props.dccConsent
        ? standardisedFamilyName
        : undefined,
      dateOfBirth: dateOfBirth,
      sex: sex,
    };

    props.onChange(result);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    givenName,
    familyName,
    standardisedGivenName,
    standardisedFamilyName,
    dateOfBirth,
    sex,
    props.dccConsent,
  ]);

  React.useEffect(() => {
    setStandardisedGivenName(givenNameTransliteration);
  }, [givenNameTransliteration]);

  React.useEffect(() => {
    setStandardisedFamilyName(familyNameTransliteration);
  }, [familyNameTransliteration]);

  const handleGivenNameChanged = (changedValue: string) => {
    const regEx = new RegExp(utils.pattern.name);

    if (regEx.test(changedValue)) {
      setGivenName(changedValue);
      // convert to ICAO and set the std field
      givenNameTransliterationUpdate(changedValue);
    }

    // setStandardisedName(tmpICAOValue.substring(0, tmpICAOValue.length > 50 ? 50 : tmpICAOValue.length));
  };

  const handleFamilyNameChanged = (changedValue: string) => {
    const regEx = new RegExp(utils.pattern.name);

    if (regEx.test(changedValue)) {
      setFamilyName(changedValue);
      // convert to ICAO and set the std field
      familyNameTransliterationUpdate(changedValue);
    }
    // setStandardisedName(tmpICAOValue.substring(0, tmpICAOValue.length > 50 ? 50 : tmpICAOValue.length));
  };

  const handleStandardisedNameChanged = (
    changedValue: string,
    setStandardisedName: (value: string) => void
  ) => {
    const upperCaseChangedValue = changedValue.toUpperCase();

    if (utils.isStandardisedNameValid(upperCaseChangedValue)) {
      setStandardisedName(upperCaseChangedValue);
    }
  };

  const handleDateOfBirthChange = (evt: Date | [Date, Date] | null) => {
    const date = handleDateChange(evt);
    setDateOfBirth(date);
  };

  const handleDateChange = (evt: Date | [Date, Date] | null) => {
    let date: Date;

    if (Array.isArray(evt)) date = evt[0];
    else date = evt as Date;

    if (date) {
      date.setHours(12);
    }

    return date;
  };

  return (
    <>
      {/* first name input */}
      <FormGroupInput
        controlId='formGivenNameInput'
        title={t('translation:first-name')}
        value={givenName}
        onChange={(evt: any) => handleGivenNameChanged(evt.target.value)}
        required
        maxLength={50}
      />

      {/* name input */}
      <FormGroupInput
        controlId='formNameInput'
        title={t('translation:name')}
        value={familyName}
        onChange={(evt: any) => handleFamilyNameChanged(evt.target.value)}
        required
        maxLength={50}
      />

      <hr />

      <Collapse in={props.dccConsent}>
        <div>
          {/* standardised first name input */}
          <FormGroupInput
            controlId='formStandadisedGivenNameInput'
            title={t('translation:standardised-first-name')}
            value={standardisedGivenName}
            onChange={(evt: any) =>
              handleStandardisedNameChanged(
                evt.target.value,
                setStandardisedGivenName
              )
            }
            required={props.dccConsent}
            pattern={utils.pattern.standardisedName}
            maxLength={150}
            prepend='i'
            lableAlign='end'
            tooltip={t('translation:standardised-first-name-tooltip')}
            infoText={
              <h5>
                <strong>{t('translation:query-id-card')}</strong>
              </h5>
            }
          />

          {/*standardised name input */}
          <FormGroupInput
            controlId='formStandadisedNameInput'
            title={t('translation:standardised-name')}
            value={standardisedFamilyName}
            onChange={(evt: any) =>
              handleStandardisedNameChanged(
                evt.target.value,
                setStandardisedFamilyName
              )
            }
            required={props.dccConsent}
            pattern={utils.pattern.standardisedName}
            maxLength={150}
            prepend='i'
            tooltip={t('translation:standardised-name-tooltip')}
          />
          <hr />
        </div>
      </Collapse>

      {/* date of birth input */}
      <Form.Group
        as={Row}
        controlId='formDateOfBirthInput'
        className='pb-3 mb-0'
      >
        <Form.Label className='input-label ' column xs='5' sm='3'>
          {t('translation:date-of-birth') + '*'}
        </Form.Label>

        <Col xs='7' sm='9' className='d-flex'>
          <DatePicker
            selected={dateOfBirth}
            onChange={handleDateOfBirthChange}
            locale='de'
            dateFormat={utils.pickerDateFormat}
            isClearable
            placeholderText={t('translation:date-of-birth')}
            className='qt-input form-control'
            wrapperClassName='align-self-center'
            showMonthDropdown
            showYearDropdown
            dropdownMode='select'
            maxDate={new Date()}
            minDate={new Date(1900, 0, 1, 12)}
            openToDate={new Date(1990, 0, 1)}
            required
          />
        </Col>
      </Form.Group>

      {/* sex input */}
      <Row>
        <Form.Label className='input-label txt-no-wrap' column xs='5' sm='3'>
          {t('translation:sex') + '*'}
        </Form.Label>

        <Col xs='7' sm='9' className='d-flex'>
          <Row>
            <FormGroupInlineRadio
              controlId='sex-radio1'
              name='sex-radios'
              title={t('translation:male')}
              checked={sex === Sex.MALE}
              onChange={() => setSex(Sex.MALE)}
            />

            <FormGroupInlineRadio
              controlId='sex-radio2'
              name='sex-radios'
              title={t('translation:female')}
              checked={sex === Sex.FEMALE}
              onChange={() => setSex(Sex.FEMALE)}
              required={true}
            />

            <FormGroupInlineRadio
              controlId='sex-radio3'
              name='sex-radios'
              title={t('translation:diverse')}
              checked={sex === Sex.DIVERSE}
              onChange={() => setSex(Sex.DIVERSE)}
            />
          </Row>
        </Col>
      </Row>
    </>
  );
}
Example #7
Source File: user-table.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
UserTable = (props: any) => {

    // const context = React.useContext(AppContext);

    const { t } = useTranslation();
    const { keycloak } = useKeycloak();

    const handleSuccess = () => {
        setIsUserSuccessfullUpdated(true);
        setIsUserCreationError(false);
        setTimeout(setShowUserModal, 300, false);
        setShowConfirm(false);
    }

    const [bUsers,
        // refreshUsers,
        createUser,
        readUser,
        updateUser,
        deleteUser] = useGetUsers(handleSuccess, props.handleError);

    const [users, setUsers] = React.useState<IDisplayUser[]>([]);
    const [reload, setReload] = React.useState(true);

    const [showUserModal, setShowUserModal] = React.useState(false);
    const [isUserSuccessfullUpdated, setIsUserSuccessfullUpdated] = React.useState(false);
    const [isUserCreationError, setIsUserCreationError] = React.useState(false);
    const [editUser, setEditUser] = React.useState<IDisplayUser>(emptyUser);
    const [ownUserId, setOwnUserId] = React.useState<string>('');

    const [showConfirm, setShowConfirm] = React.useState(false);
    const [confirmMessage, setConfirmMessage] = React.useState('');
    const [confirmTitle, setConfirmTitle] = React.useState('');
    const [confirmHandle, setConfirmHandle] = React.useState<() => void>();

    // set user name from keycloak
    React.useEffect(() => {

        if (keycloak.idTokenParsed) {
            setOwnUserId((keycloak.idTokenParsed as any).sub ?? '');
        }

    }, [keycloak])

    React.useEffect(() => {
        if (bUsers) {
            setUsers(bUsers);
            setEditUser({ ...emptyUser });
        }
    }, [bUsers]);

    React.useEffect(() => {
        if (props.userReload) {
            users.forEach((user => updateDisplayUser(user, false)));
            props.setUserReload(false);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [props.userReload]);

    React.useEffect(() => {
        if (props.groupNodes && users && users.length > 0 && reload) {
            setReload(false);
            users.forEach((user => updateDisplayUser(user, true)));
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [JSON.stringify(props.groupNodes), users, reload]);

    const sortUsers = () => {
        users.sort((a, b) => {
            const nameA = a.username.toUpperCase(); // ignore upper and lowercase
            const nameB = b.username.toUpperCase(); // ignore upper and lowercase
            if (nameA < nameB) {
                return -1;
            }
            if (nameA > nameB) {
                return 1;
            }

            // names must be equal
            return 0;
        });
    }

    const addDisplayUser = (user: IDisplayUser) => {
        setGroupPath(user);
        user.displayRole = getDisplayRole(user);
        users.push(user);
        sortUsers();

        setUsers(users);
    }

    const updateDisplayUser = (user: IDisplayUser, withApi: boolean, onSuccess?: () => void) => {
        // set all groupPath for display
        setGroupPath(user);

        // set all rollDisplay async
        if (withApi) {
            readUser(user)
                .then((response) => {
                    user.roleCounter = response.data.roleCounter;
                    user.roleLab = response.data.roleLab;

                    user.displayRole = getDisplayRole(user);
                })
                .finally(() => {
                    updateUsers(user);
                    if (onSuccess) {
                        onSuccess();
                    }
                })
        }
        else {
            updateUsers(user);
        }
    }

    const updateUsers = (user: IDisplayUser | IUser) => {
        const _users: IDisplayUser[] = [...users];

        _users[_users.findIndex(_user => user.id === _user.id)] = { ...user };

        setUsers(_users);
    }
    const removeUsers = (user: IDisplayUser | IUser) => {
        users.splice(users.findIndex(_user => user.id === _user.id), 1);
        setUsers(users);
    }

    const userUpdate = (user: IUser) => {
        if (editUser && editUser.username) {
            const fuser = users.find(u => u.username === user.username);

            if (!user.password) {
                user.password = undefined;
            }

            updateUser(user)
                .then(() => {
                    if (
                        fuser
                        && fuser.subGroup !== user.subGroup
                        && keycloak.token
                        && user.subGroup
                    ) {
                        addUserToGroup(user.id, user.subGroup, keycloak.token)
                            .then(() => {
                                updateDisplayUser(user, true, handleSuccess);
                            })
                            .catch(e => {
                                props.handleError(e);
                            });
                    } else {
                        updateDisplayUser(user, true, handleSuccess);
                    }
                })

        } else {
            const newUser: any = { ...user };

            createUser(newUser)
                .then((response) => {
                    const displayUser: IDisplayUser = { ...response.data };
                    addDisplayUser(displayUser);
                    handleSuccess();
                })
                .catch(e => {
                    if (e && e.message && (e.message as string).includes('409')) {
                        setIsUserCreationError(true);
                    }
                    else {
                        props.handleError(e);
                    }
                })
        }
    }

    const startEditUser = (user: IUser) => {
        setEditUser({ ...user });
        setShowUserModal(true);
    }

    const handleDeleteUser = (user: IDisplayUser) => {
        setConfirmTitle(t('translation:delete-user-title', { userName: user.username }));
        setConfirmMessage('');
        setShowConfirm(true);

        const handle = () => {
            if (keycloak.token && user.username) {
                deleteUser(user.id)
                    .then(() => {
                        removeUsers(user);
                        handleSuccess();
                    })
                    .catch(e => {
                        props.handleError(e);
                    })
            }
        };
        // need to wrap a function again because react apply each function passed to hook
        setConfirmHandle(() => handle);
    }

    const getDisplayRole = (user: IUser) => {
        let roleString = '';

        if (user.roleLab) {
            roleString = t('translation:lab');
        }

        if (user.roleCounter) {
            if (roleString) {
                roleString += ', ';
            }
            roleString += t('translation:counter');
        }

        return roleString;
    }

    const setGroupPath = (user: IDisplayUser) => {
        if (user.subGroup) {
            const _groupName = getGroupPath(user.subGroup);

            if (_groupName) {
                user.displayGroup = _groupName;
            }
            else {
                user.subGroup = '';
                user.displayGroup = '';
            }
        }
        else {
            user.displayGroup = '';
        }
    }

    const getGroupPath = (groupId: string | null): string => {
        let groupName = ''

        if (props.groupNodes && groupId) {
            const fNode = (props.groupNodes as IGroupNode[]).find(gnode => gnode.group.id === groupId);

            if (fNode) {
                groupName = fNode.group.path;
            }
        }

        return groupName;
    }

    return (<>
        {
            !(users && users.length > 0)
                ? <CwaSpinner background='#eeeeee' />
                : <Collapse appear={true} in={true}>
                    <Container className='p-0 '>
                        <Table bordered hover responsive>
                            <thead>
                                <tr>
                                    <th>{t('translation:user-name')}</th>
                                    <th>{t('translation:first-name')}</th>
                                    <th>{t('translation:name')}</th>
                                    <th>{t('translation:group')}</th>
                                    <th>{t('translation:permission')}</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>{
                                users.map((u, i) =>
                                    <tr key={i}>
                                        <td>{u.subGroup || (ownUserId && u.id === ownUserId)
                                            ? <></>
                                            : <OverlayTrigger
                                                placement='top-end'
                                                overlay={
                                                    <Tooltip id='no-group-tooltip'>
                                                        {t('translation:no-group-tooltip')}
                                                    </Tooltip>
                                                }
                                            >
                                                <span className='ff-fa px-1'>&#xf071; </span>
                                            </OverlayTrigger>}
                                            {u.username}</td>
                                        <td>{u.firstName}</td>
                                        <td>{u.lastName}</td>
                                        <td>
                                            {
                                                u.displayGroup
                                                    ? u.displayGroup
                                                    : u.subGroup
                                                        ? <Spinner
                                                            animation="border"
                                                            className='d-flex mx-auto'
                                                            size="sm"
                                                            role="status"
                                                            aria-hidden="true"
                                                            variant='primary'
                                                        />
                                                        : <></>
                                            }
                                        </td>
                                        <td>{
                                            u.displayRole !== undefined
                                                ? u.displayRole
                                                : <Spinner
                                                    animation="border"
                                                    className='d-flex mx-auto'
                                                    size="sm"
                                                    role="status"
                                                    aria-hidden="true"
                                                    variant='primary'
                                                />
                                        }
                                        </td>
                                        <td className='td-btn'>
                                            <Row className='m-0 justify-content-around'>
                                                <Button
                                                    className="btn-icon edit-icon"
                                                    onClick={() => startEditUser({ ...u })}
                                                >
                                                </Button>
                                                <Button className="btn-icon delete-icon"
                                                    onClick={() => handleDeleteUser(u)}
                                                    disabled={!(ownUserId && u.id !== ownUserId)}
                                                />
                                            </Row>
                                        </td>
                                    </tr>
                                )
                            }</tbody>
                        </Table>

                        <Button
                            className='btn-add'
                            size="sm"
                            variant="light"
                            onClick={() => { setEditUser({ ...emptyUser }); setShowUserModal(true) }}>
                            <img className='mr-2' src={imageAdd} alt="Hinzufügen" />
                            {t('translation:add-user')}
                        </Button>
                    </Container>
                </Collapse>
        }


        <UserModal
            show={showUserModal}
            groups={props.groupNodes}
            handleOk={userUpdate}
            user={editUser}
            onEnter={() => setIsUserSuccessfullUpdated(false)}
            isSuccess={isUserSuccessfullUpdated}
            isCreationError={isUserCreationError}
            resetError={() => setIsUserCreationError(false)}
            onCancel={() => setShowUserModal(false)}
            onExit={
                () => {
                    setEditUser({ ...emptyUser });
                    setIsUserSuccessfullUpdated(false);
                    setIsUserCreationError(false);
                }
            }
        />
        <ConfirmModal
            show={showConfirm}
            title={confirmTitle}
            message={confirmMessage}
            onCancel={() => {
                setConfirmHandle(undefined);
                setShowConfirm(false);
            }}
            handleOk={() => {
                if (confirmHandle) {
                    confirmHandle();
                }
            }}
        />
    </>
    )

}
Example #8
Source File: record-patient-data.component.tsx    From cwa-quick-test-frontend with Apache License 2.0 4 votes vote down vote up
RecordPatientData = (props: any) => {

    const context = React.useContext(AppContext);
    const { t } = useTranslation();

    const { keycloak } = useKeycloak();

    const [isInit, setIsInit] = React.useState(false)
    const [uuIdHash, setUuIdHash] = React.useState('');

    const [isBack, setIsBack] = React.useState(true);
    const isBackRef = React.useRef(isBack);
    isBackRef.current = isBack;

    const [processId, setProcessId] = React.useState('');
    const processIdRef = React.useRef(processId);
    processIdRef.current = processId;

    const [person, setPerson] = React.useState<IPersonData>();
    const [address, setAddress] = React.useState<IAddressData>();

    const [pcrEnabled, setPcrEnabled] = React.useState(false);
    const [testType, setTestType] = React.useState(TestType.RAT);

    const [phoneNumber, setPhoneNumber] = React.useState('');
    const [emailAddress, setEmailAddress] = React.useState('');
    const [additionalInfo, setAdditionalInfo] = React.useState('');
    const [consent, setConsent] = React.useState(false);
    const [dccConsent, setDccConsent] = React.useState(false);
    const [dccNoConsent, setDccNoConsent] = React.useState(false);
    const [persDataInQR, setIncludePersData] = React.useState(false)
    const [privacyAgreement, setPrivacyAgreement] = React.useState(false)
    const [validated, setValidated] = React.useState(false);



    const handleError = (error: any) => {
        let msg = '';

        if (error) {
            msg = error.message
        }

        if (error && error.message && (error.message as string).includes('412')) {
            msg = t('translation:no-group-error');
        }
        props.setError({ error: error, message: msg, onCancel: context.navigation!.toLanding });
    }

    const handleDelete = () => { deleteQuicktest(processIdRef.current); }
    const [uuid, deleteQuicktest] = useGetUuid(props?.quickTest?.uuId, undefined, handleError);
    useOnUnload(() => handleDelete);


    React.useEffect(() => {
        return () => {
            if (isBackRef.current) {
                handleDelete();
            }
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    React.useEffect(() => {

        if (keycloak.idTokenParsed) {
            setPcrEnabled(!!(keycloak.idTokenParsed as any).pcr_enabled);
        }

    }, [keycloak])

    // set values from props or new uuid on mount
    React.useEffect(() => {
        if (props.quickTest) {
            const p = props.quickTest;

            setConsent(p.processingConsens);
            setIncludePersData(p.includePersData);
            setPrivacyAgreement(p.privacyAgreement);
            setPhoneNumber(p.phoneNumber);
            if (p.emailAddress) {
                setEmailAddress(p.emailAddress);
            }
            if (p.additionalInfo) {
                setAdditionalInfo(p.additionalInfo);
            }
            setDccConsent(p.dccConsent);
            setDccNoConsent(!p.dccConsent);
            setTestType(p.testType);
        }

        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [props.quickTest]);

    // set hash from uuid
    React.useEffect(() => {
        if (uuid) {
            setUuIdHash(sha256(uuid).toString());
        }
    }, [uuid]);

    // set process id from hash
    React.useEffect(() => {
        setProcessId(utils.shortHash(uuIdHash));
    }, [uuIdHash]);

    // set ready state for spinner
    React.useEffect(() => {
        if (processId && context.navigation && context.valueSets) {
            setIsInit(true);
        }
    }, [processId, context.navigation, context.valueSets])

    const handleDccConsentChange = (evt: any) => {
        setDccConsent(true)
        setDccNoConsent(false);
    }

    const handleDccNoConsentChange = (evt: any) => {
        setDccConsent(false)
        setDccNoConsent(true);
    }

    const handleConsentChange = (evt: any) => {
        setConsent(!consent)
        setIncludePersData(false);
    }

    const handlePersDataInQRChange = (evt: any) => {
        setIncludePersData(!persDataInQR);
        setConsent(false);
    }

    const handleCancel = () => {
        props.setQuickTest(undefined);
        context.navigation!.toLanding();
    }

    const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
        const form = event.currentTarget;

        event.preventDefault();
        event.stopPropagation();

        setValidated(true);
        setIsBack(false);

        if (form.checkValidity() && person) {
            props.setQuickTest({
                personData: person,
                addressData: address,
                processingConsens: consent,
                uuId: uuid,
                includePersData: persDataInQR,
                privacyAgreement: privacyAgreement,
                phoneNumber: phoneNumber,
                emailAddress: emailAddress || undefined,
                dccConsent: dccConsent,
                additionalInfo: additionalInfo || undefined,
                testType: testType
            })
            setTimeout(context.navigation!.toShowRecordPatient, 200);
        }

    }

    return (
        !(isInit && context && context.valueSets)
            ? <CwaSpinner />
            : <Fade appear={true} in={true} >
                <Container className='form-flex p-0 '>
                    <Row id='process-row'>
                        <span className='font-weight-bold mr-2'>{t('translation:process')}</span>
                        <span>{processId}</span>
                    </Row>
                    <Card id='data-card'>

                        <Form className='form-flex' onSubmit={handleSubmit} validated={validated}>

                            {/*
                            header with title and id card query
                            */}
                            <CardHeader idCard={true} title={t('translation:record-result2')} />

                            {/*
                            content area with patient inputs and check box
                            */}
                            <Card.Body id='data-body' className='pt-0'>

                                {/* dccConsent */}
                                <Row className='yellow'>
                                    <Col className='p-0' xs='5' sm='3'>
                                        <Row className='m-0 mb-2'>
                                            <Col className='p-0' xs='auto'>
                                                <Form.Label className='input-label pl-1'>
                                                    {t('translation:testZertifikat')}*
                                                </Form.Label>
                                            </Col>
                                            <Col className='p-0 jcc-xs-jcfs-lg ml-lg-2 d-flex'>
                                                <Image className="eu-flag" src={eu_logo} />
                                            </Col>
                                        </Row>
                                    </Col>
                                    <Col xs='7' sm='9'>
                                        <Row className='m-0'>
                                            <Form.Label className='input-label m-0'>{t('translation:dccConsent')}</Form.Label>
                                        </Row>
                                        <Collapse in={dccConsent}>
                                            <Row className='m-0 my-1'>
                                                <Form.Label className='input-label text-justify m-0'>
                                                    <Form.Label className='input-label mb-0 mr-2'>
                                                        &#xf071;
                                                    </Form.Label>
                                                    {t('translation:dccConsent-cwa-only')}
                                                </Form.Label>
                                            </Row>
                                        </Collapse>
                                        <Row className='m-0 mb-2'>
                                            <FormGroupDccConsentRadio controlId='dccConsent-radio1' name="dccConsent-radios" title={t('translation:ja')}
                                                checked={dccConsent}
                                                onChange={handleDccConsentChange}
                                                required={true}
                                            />

                                            <FormGroupDccConsentRadio controlId='dccConsent-radio2' name="dccConsent-radios" title={t('translation:nein')}
                                                checked={dccNoConsent}
                                                onChange={handleDccNoConsentChange}
                                                required={true}
                                            />
                                        </Row>
                                    </Col>
                                </Row>

                                <hr />
                                {!pcrEnabled
                                    ? <></>
                                    : <>
                                        <Row>
                                            <Form.Label className='input-label txt-no-wrap' column xs='5' sm='3'>{t('translation:test-type') + '*'}</Form.Label>

                                            <Col xs='7' sm='9' className='d-flex'>
                                                <Row>
                                                    <FormGroupInlineRadio controlId='test-type1' name="test-type-radios" title={t(`translation:${TestType.RAT}`)} sm='6'
                                                        checked={testType === TestType.RAT}
                                                        onChange={() => setTestType(TestType.RAT)}
                                                    />

                                                    <FormGroupInlineRadio controlId='test-type2' name="test-type-radios" title={t(`translation:${TestType.PCR}`)} sm='6'
                                                        checked={testType === TestType.PCR}
                                                        onChange={() => setTestType(TestType.PCR)}
                                                        required={true}
                                                    />
                                                </Row>
                                            </Col>
                                        </Row>
                                        <hr />
                                    </>
                                }

                                <PersonInputs quickTest={props.quickTest} onChange={setPerson} dccConsent={dccConsent} onDccChanged={setDccConsent} />

                                <hr />

                                {/* address input */}
                                <AddressInputs quickTest={props.quickTest} onChange={setAddress} />

                                <hr />

                                {/* phone number input */}

                                < FormGroupInput controlId='formPhoneInput' title={t('translation:phone-number')}
                                    value={phoneNumber}
                                    onChange={(evt: any) => setPhoneNumber(evt.target.value)}
                                    type='tel'
                                    required
                                    pattern={utils.pattern.tel}
                                    maxLength={79}
                                />

                                < FormGroupInput controlId='formEmailInput' title={t('translation:email-address')}
                                    value={emailAddress}
                                    onChange={(evt: any) => setEmailAddress(evt.target.value)}
                                    type='email'
                                    pattern={utils.pattern.eMail}
                                    minLength={5}
                                    maxLength={255}
                                />

                                < FormGroupInput controlId='formAdditionalInfo' title={t('translation:additional-info')}
                                    value={additionalInfo}
                                    onChange={(evt: any) => setAdditionalInfo(evt.target.value)}
                                    type='text'
                                    minLength={1}
                                    maxLength={250}
                                    prepend='i'
                                    tooltip={t('translation:additional-info-tooltip')}
                                />

                                <hr />
                                {/* processing consent check box */}
                                <FormGroupConsentCkb controlId='formConsentCheckbox' title={t('translation:processing-consent-title')}
                                    accordion={t('translation:processing-consent')}
                                    onClick={handleConsentChange}
                                    onChange={handleConsentChange}
                                    type='radio'
                                    name="check-radios"
                                    checked={consent}
                                    required={dccConsent}
                                />
                                <FormGroupConsentCkb controlId='formKeepPrivateCheckbox' title={t('translation:patientdata-exclude-title')}
                                    accordion={t('translation:patientdata-exclude')}
                                    onClick={handlePersDataInQRChange}
                                    onChange={handlePersDataInQRChange}
                                    type='radio'
                                    name="check-radios"
                                    checked={persDataInQR}
                                    required={dccConsent}
                                />
                                <FormGroupConsentCkb controlId='formDataPrivacyCheckbox' title={t('translation:data-privacy-approve')}
                                    onChange={(evt: any) => setPrivacyAgreement(evt.currentTarget.checked)}
                                    type='checkbox'
                                    checked={privacyAgreement}
                                    required
                                />
                            </Card.Body>

                            {/*
    footer with clear and nex button
    */}
                            <CardFooter handleCancel={handleCancel} />

                        </Form>
                    </Card>
                </Container>
            </Fade>
    )
}
Example #9
Source File: index.tsx    From nouns-monorepo with GNU General Public License v3.0 4 votes vote down vote up
ProfileActivityFeed: React.FC<ProfileActivityFeedProps> = props => {
  const { nounId } = props;

  const MAX_EVENTS_SHOW_ABOVE_FOLD = 5;

  const [truncateProposals, setTruncateProposals] = useState(true);

  const { loading, error, data } = useQuery(nounVotingHistoryQuery(nounId));
  const {
    loading: proposalTimestampLoading,
    error: proposalTimestampError,
    data: proposalCreatedTimestamps,
  } = useQuery(createTimestampAllProposals());

  const nounCanVoteTimestamp = useNounCanVoteTimestamp(nounId);

  const { data: proposals } = useAllProposals();

  if (loading || !proposals || !proposals.length || proposalTimestampLoading) {
    return <></>;
  } else if (error || proposalTimestampError) {
    return (
      <div>
        <Trans>Failed to fetch Noun activity history</Trans>
      </div>
    );
  }

  const nounVotes: { [key: string]: NounVoteHistory } = data.noun.votes
    .slice(0)
    .reduce((acc: any, h: NounVoteHistory, i: number) => {
      acc[h.proposal.id] = h;
      return acc;
    }, {});

  const filteredProposals = proposals.filter((p: Proposal, id: number) => {
    return (
      parseInt(proposalCreatedTimestamps.proposals[id].createdTimestamp) >
        nounCanVoteTimestamp.toNumber() ||
      (p.id && nounVotes[p.id])
    );
  });

  return (
    <Section fullWidth={false}>
      <Col lg={{ span: 10, offset: 1 }}>
        <div className={classes.headerWrapper}>
          <h1>
            <Trans>Activity</Trans>
          </h1>
        </div>
        {filteredProposals && filteredProposals.length ? (
          <>
            <Table responsive hover className={classes.aboveTheFoldEventsTable}>
              <tbody className={classes.nounInfoPadding}>
                {filteredProposals?.length ? (
                  filteredProposals
                    .slice(0)
                    .reverse()
                    .slice(0, MAX_EVENTS_SHOW_ABOVE_FOLD)
                    .map((p: Proposal, i: number) => {
                      const vote = p.id ? nounVotes[p.id] : undefined;
                      return <NounProfileVoteRow proposal={p} vote={vote} key={i} />;
                    })
                ) : (
                  <LoadingNoun />
                )}
              </tbody>
            </Table>
            <Collapse in={!truncateProposals}>
              <div>
                <Table responsive hover>
                  <tbody className={classes.nounInfoPadding}>
                    {filteredProposals?.length ? (
                      filteredProposals
                        .slice(0)
                        .reverse()
                        .slice(MAX_EVENTS_SHOW_ABOVE_FOLD, filteredProposals.length)
                        .map((p: Proposal, i: number) => {
                          const vote = p.id ? nounVotes[p.id] : undefined;
                          return <NounProfileVoteRow proposal={p} vote={vote} key={i} />;
                        })
                    ) : (
                      <LoadingNoun />
                    )}
                  </tbody>
                </Table>
              </div>
            </Collapse>

            {filteredProposals.length <= MAX_EVENTS_SHOW_ABOVE_FOLD ? (
              <></>
            ) : (
              <>
                {truncateProposals ? (
                  <div
                    className={classes.expandCollapseCopy}
                    onClick={() => setTruncateProposals(false)}
                  >
                    <Trans>Show all {filteredProposals.length} events </Trans>{' '}
                    <FontAwesomeIcon icon={faChevronDown} />
                  </div>
                ) : (
                  <div
                    className={classes.expandCollapseCopy}
                    onClick={() => setTruncateProposals(true)}
                  >
                    <Trans>Show fewer</Trans> <FontAwesomeIcon icon={faChevronUp} />
                  </div>
                )}
              </>
            )}
          </>
        ) : (
          <div className={classes.nullStateCopy}>
            <Trans>This Noun has no activity, since it was just created. Check back soon!</Trans>
          </div>
        )}
      </Col>
    </Section>
  );
}