box/box-ui-elements

use latest version of box-ui-elements .when i select the file in box ui popup select and cancel button not showing

boopathi2710 opened this issue · 6 comments

Desktop (please complete the following information):
Model : Acer Aspire E5-573 Intel® Core™ i5-5200U CPU @ 2.20GHz × 4

  • OS: Ubuntu 19.10
  • Browser Chrome
  • Version Version 95.0.4638.54 (Official Build) (64-bit)

Smartphone (please complete the following information):

  • Device: N/A
  • OS: N/A
  • Browser N/A
  • Version N/A

Steps to reproduce the problem:

  1. I used latest level of box-ui-elements.
    2.In the React code used this to invoke the File picker
    3.I see the Box File Picker as below
    Screenshot from 2021-11-24 15-51-56
    4.upon selecting file ,the selction option goes way

Screenshot from 2021-11-24 15-53-42

What is the expected behavior? (Screenshots can be helpful here)
1.The expected behaviour is when the upon file selection, the user must be able to see the select and cancel button
Screenshot from 2021-11-24 15-55-51

What went wrong? (Screenshots, console logs, or HAR files can be helpful here)
Screenshot from 2021-11-24 16-00-41
har.txt

Link to application or sample code:

`import * as React from 'react';
import { isEmpty, pathOr, lensPath, set, equals, join } from 'ramda';
import BoxLogo from 'src/assets/uploads/box.svg';
import BoxLogin from 'src/features/Auth/LoginProviders/Box';
import Popup from 'reactjs-popup';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { connect, MapStateToProps } from 'react-redux';
import { ApplicationState } from 'src/store/ApplicationState.d';
import {
  START_APPLICATION_HOME,
  BOX_CLIENT_ID,
  BOX_CLIENT_SECRET,
} from 'src/constants';
import { compose } from 'recompose';
import {
  DOCUMENT_REPRESENTS_NOTHING,
  doNothing,
  DOCUMENT_REPRESENTS_PROFIT_AND_LOSS,
  META_DATA,
} from 'src/services/constants';

import ContentPicker from 'box-ui-elements/es/elements/content-picker/ContentPicker';
import messages from 'box-ui-elements/i18n/en-US';
import 'box-ui-elements/dist/picker.css';
import { DriveAccess } from 'src/features/Uploads/FileStack/Driver';
import {
  mkFilesUpload,
  _onLoanTypeUrl,
  getRedirectFormationURL,
  getEventLabelNameForCloudStorage,
} from 'src/features/Uploads/utilities';
import { BOX_COULD } from 'src/features/Uploads/FileStack/constants';
import { sendCreateCloudStorageEvent } from 'src/utilities/ga';
import { updateUserSpecificIntentForThisIntentAndMoveToNextIntent } from 'src/features/core/ChatEngine/Bot/SimpleBotService';
import { ApiFieldError } from 'src/types';

interface Props {
  redirectTo: string;
  hasColumnResize: any;
  accounts: any;
  intent: any;
}

interface State {
  submitting: boolean;
  accessToken: string;
  config: DriveAccess;
  hasBrowser: boolean;
  open: boolean;
  errors?: ApiFieldError[];
}

type CombinedProps = StateProps & Props & RouteComponentProps<{}>;

class BoxDrawer extends React.Component<CombinedProps, State> {
  mounted: boolean = false;
  static defaultConfigState = {
    folderId: '',
    fileName: '',
    fileId: '',
    fileLink: '',
    mimeType: '',
    sizeBytes: 0,
  };

  state: State = {
    submitting: false,
    accessToken: '',
    config: BoxDrawer.defaultConfigState,
    hasBrowser: false,
    open: false,
  };

  componentDidMount() {
    this.mounted = true;
  }

  componentWillUnmount() {
    this.mounted = false;
  }

  loggedIn = (accessToken: any) => {
    const hasBrowser = !isEmpty(accessToken);

    if (accessToken) {
      this.setState({
        accessToken,
        hasBrowser,
      });
    }
  };

  handleFailure = (err: any) => {
    if (err) {
      const errors: ApiFieldError[] = [
        {
          reason: 'Login with Box not successfull',
        },
      ];
      this.setState({ errors, submitting: false });
    }
  };

  closeModal = () => {
    this.setState({ open: false });
  };

  mkFilesUpload = (fileCollection: any) => {
    this.setState({
      submitting: true,
    });
    if (fileCollection.length === 0) {
      const errors = [{ reason: 'File is required', field: 'file' }];
      this.setState({
        errors,
        submitting: false,
      });
      return;
    }
    const category = pathOr(
      DOCUMENT_REPRESENTS_NOTHING,
      [META_DATA, 'category'],
      this.props.intent
    );
    const _category = equals(category, '12 Month P')
      ? DOCUMENT_REPRESENTS_PROFIT_AND_LOSS
      : category;

    const { loanRole, loanApp } = this.props;
    const { accessToken } = this.state;
    const callbacks = {
      onSuccess: () => {
        const { history } = this.props;
        if (
          equals(
            getRedirectFormationURL(this.props.location.search),
            START_APPLICATION_HOME
          )
        ) {
          this.saveCompletion();
          this.sendAnalyticsEvent();
        }
        this.sendAnalyticsEvent();
        setTimeout(() => {
          history.push(getRedirectFormationURL(this.props.location.search));
        }, 2000);
      },
      onFailure: () => {
        // single file failure action
      },
      setSubmitting: (values: any) => {
        this.setState({
          submitting: values,
        });
      },
      setError: () => {
        // single file error handle
      },
    };

    mkFilesUpload(
      fileCollection,
      _category,
      loanRole,
      accessToken,
      BOX_COULD,
      this.props.location.search,
      callbacks,
      loanApp
    ).then(() => {
      // // Over all success handle
      // const { history, redirectTo } = this.props;
      //
      // const loanType = getQueryParam(this.props.location.search, 'loanType');
      //
      // const push = redirectTo ? redirectTo : _onLoanTypeUrl(loanType);
      // if (equals(push, START_APPLICATION_HOME)) {
      //   this.saveCompletion();
      // }
      // history.push(push);
    });
  };

  handleFileSelected = (selected: any) => {
    this.onCancel(selected);
    const configs = selected.map((file: any) => {
      return compose(
        set(lensPath(['sizeBytes']), Number(pathOr('0', ['size'], file))),
        set(lensPath(['folderId']), pathOr('', ['parent', 'id'], file)),
        set(lensPath(['fileId']), pathOr('', ['id'], file)),
        set(lensPath(['fileName']), pathOr('', ['name'], file)),
        set(lensPath(['mimeType']), pathOr('', ['extension'], file))
      )({});
    });
    this.mkFilesUpload(configs);
  };

  onCancel = (_err: any) => {
    this.setState({ hasBrowser: false });
  };
  getAuthenticationToken = () => {
    const { accessToken } = this.state;
    return Promise.resolve(accessToken);
  };

  /// Moving this to a separate reducer for uploads will solve this redundant
  // code.
  saveCompletion = () => {
    const { intents, intent } = this.props;

    updateUserSpecificIntentForThisIntentAndMoveToNextIntent(
      intent,
      intents,
      'uploaded'
    );
  };

  sendAnalyticsEvent = () => {
    const { accounts } = this.props;
    const category = pathOr(
      DOCUMENT_REPRESENTS_NOTHING,
      [META_DATA, 'category'],
      this.props.intent
    );
    /// This is just a hack for now. As the render gets done before and the
    /// props set in the componentDidMount doesn't reflect here.
    const _category = equals(category, '12 Month P')
      ? DOCUMENT_REPRESENTS_PROFIT_AND_LOSS
      : category;
    const name = join(' ', [
      pathOr('', ['first_name'], accounts),
      pathOr('', ['last_name'], accounts),
    ]);
    sendCreateCloudStorageEvent(
      getEventLabelNameForCloudStorage(name, 'box upload', _category)
    );
  };

  // 1. Get the auth dispatch(GOOGLE_AUTHENTICATION_TOKEN)
  setAuthenticatedToken = (accessToken: string) => {
    // is there a better way than setting in the state
    this.setState(
      compose(
        set(lensPath(['googleAuth', 'accessToken']), accessToken),
        set(lensPath(['googleAuth', 'refreshToken']), accessToken)
      )
    );
  };

  render() {
    const { hasBrowser, accessToken } = this.state;
    const { hasColumnResize } = this.props;
    const logoUrl = 'https://s3.us-east-2.amazonaws.com/lendsmartpub/logo.png';

    /// Truly a temporary hack.
    if (hasBrowser) {
      return (
        <Popup
          trigger={
            <div className="col-md-6 col-lg-4 mb-4 mb-lg-3 pr-lg-2">
              <a href="#" className="card text-center text-decoration-none">
                <div className="card-body">
                  <BoxLogo className="img-fluid" />
                  <p className="my-2">Box</p>
                </div>
              </a>
            </div>
          }
          modal
          defaultOpen={true}
          open={this.state.open}
          onClose={this.closeModal}
          closeOnEscape
          closeOnDocumentClick
        >
          <React.Fragment>
            <span>
              <BoxLogo className="img-fluid" />
            </span>
            <ContentPicker
              language="en-US"
              messages={messages}
              token={accessToken}
              logoUrl={logoUrl}
              onCancel={this.onCancel}
              onChoose={this.handleFileSelected}
              showSelectedButton={true}
            />
          </React.Fragment>
        </Popup>
      );
    }

    return (
      <div
        className={`col-md-6 col-lg-${
          hasColumnResize ? 3 : 4
        } mb-4 mb-lg-3 pr-lg-2`}
      >
        <BoxLogin
          clientId={BOX_CLIENT_ID}
          clientSecret={BOX_CLIENT_SECRET}
          onRequest={doNothing}
          onSuccess={this.loggedIn}
          onFailure={this.handleFailure}
          buttonTheme="light_short"
          debug={true}
        />
      </div>
    );
  }
}

interface StateProps {
  loanRole: string;
  intents: any;
  loanApp: any;
}

const mapStateToProps: MapStateToProps<StateProps, {}, ApplicationState> = (
  state,
  _ownProps
) => ({
  loanRole: pathOr(
    '',
    ['loanAppRole', 'loanAppRole', 'metadata', 'name'],
    state
  ),
  accounts: pathOr({}, ['accounts', 'data'], state),
  intents: pathOr({}, ['userSpecificIntent', 'data'], state),
  loanApp: pathOr({}, ['__resources', 'loanApp', 'data'], state),
});

const connected = connect(mapStateToProps, undefined);
const enhanced = compose(withRouter, connected);

export default enhanced(BoxDrawer);

`
If relevant, link to file (or attach file here)

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.
Please refer above.
Additional context
Add any other context about the problem here.

hello! we were unable to reproduce this issue. please reopen if you're still experiencing this on v15. thanks!

@tjuanitas Hi there! I'm getting this same UI bug + it seems like my props are not being passed through (neither chooseButtonLabel or onChoose are being set/called back). I am using React 18.2.0 and box-ui-elements 18.1.0

Hi @roshcagra ! interesting, can you provide a snippet of the props you're passing to ContentPicker? I'll try to reproduce locally.

side note: i'm somewhat surprised that box-ui-elements worked in React 18. did you have to resolve any issues related to that when you set up your app?

@tjuanitas Hey! Thanks for the quick response: this is my setup:

import ContentPicker from 'box-ui-elements/es/elements/content-picker';
import messages from 'box-ui-elements/i18n/en-US';

...

const onChoose = (stuff: any) => {
    console.log(stuff);
  };

<IntlProvider locale="en">
    <ContentPicker
      token={'***'}
      language={'en-US'}
      messages={messages}
      onChoose={onChoose}
      chooseButtonLabel={'Choose'}
    />
</IntlProvider>

...

The only issue I had was that I didn't have sass installed, otherwise no problems during setup. I also installed all of the peerDependencies.

the props look good to me and seem to be working correctly in my demo. I'm running react: 17.0.2 and box-ui-elements: 17.0.0-beta.1, here's my code:

import { IntlProvider } from "react-intl";

import ContentPicker from "box-ui-elements/es/elements/content-picker";
import messages from "box-ui-elements/i18n/en-US";

const ContentPickerDemo = () => {
  const onChoose = () => {
    console.log('onChoose is clicked');
  };

  return (
    <IntlProvider locale="en">
      <ContentPicker
        chooseButtonLabel={"Test"}
        language={"en-US"}
        messages={messages}
        onChoose={onChoose}
        token={***}
      />
    </IntlProvider>
  );
};
Screenshot 2023-11-06 at 5 40 32 PM

An important note is that the buttons on the bottom right are icon buttons now instead of text buttons from a previous design. The chooseButtonLabel prop only modifies the text in the tooltip.

If you're looking for text buttons instead of icon buttons, you can pass a renderCustomActionButtons prop:

renderCustomActionButtons?: ({
onCancel: Function,
onChoose: Function,
selectedCount: number,
selectedItems: BoxItem[],
}) => Node,

import Button from "box-ui-elements/es/components/button";
import PrimaryButton from "box-ui-elements/es/components/primary-button";

const ContentPickerDemo = () => {
  const onChoose = () => {
    console.log("onChoose is clicked");
  };

  const renderCustomActionButtons = ({ onCancel, onChoose }: any) => {
    return (
      <div>
        <Button onClick={onCancel} type="button">
          Cancel
        </Button>
        <PrimaryButton onClick={onChoose} type="button">
          Choose
        </PrimaryButton>
      </div>
    );
  };

  return (
    <IntlProvider locale="en">
      <ContentPicker
        onChoose={onChoose}
        renderCustomActionButtons={renderCustomActionButtons}
        token={***}
      />
    </IntlProvider>
  );
};

If none of the above is working as you expect, it could be related to React 18 (although that sounds unlikely if you're able to render other parts of the UI). tbh I haven't tested box-ui-elements in newer versions of React so not sure if there are issues

If you bump up your react version to 18+ do you get any of the UI issues I'm seeing?