@material-ui/lab#Autocomplete JavaScript Examples

The following examples show how to use @material-ui/lab#Autocomplete. 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: index.js    From flame-coach-web with MIT License 6 votes vote down vote up
SearchClient = ({
  clients,
  clientDefault,
  searchSelectedHandler,
  inputRef,
  disabled,
  ...rest
}) => {
  return (
    <Autocomplete
      id="search-client"
      freeSolo
      options={clients.map((option) => option)}
      onChange={(event, client) => {
        searchSelectedHandler(client);
      }}
      value={clients.find(client => client.identifier === clientDefault)}
      disabled={disabled}
      getOptionLabel={(option) => `${option.firstname} ${option.lastname}`}
      renderInput={(params) => (
        <TextField {...rest} {...params} label="Client" name="client"
                   variant="outlined" inputRef={inputRef}/>
      )}
    />
  );
}
Example #2
Source File: KbSearch.js    From dataqa with GNU General Public License v3.0 6 votes vote down vote up
render() {
    const { classes } = this.props;

    return (
      <Autocomplete
        classes={{ inputRoot: classes.inputRoot }}
        options={this.state.options}
        getOptionLabel={option => option.name}
        onChange={this.addSuggestion}
        renderInput={params => <TextField
                                  {...params}
                                  label={""}
                                  required={false}
                               />
        }
        onInputChange={this.onInputChange}
        getOptionSelected={(value, option) => value.name == option.name}
        autoSelect={true}
        inputValue={this.state.inputValue}
        disableClearable={true}
        value={this.state.value}
      />
    )
  }
Example #3
Source File: expiries.jsx    From GraphVega with MIT License 6 votes vote down vote up
render() {
    return(
      <Autocomplete
        noOptionsText={"Select an underlying from the search first!"}
        options={this.state.expirations}
        getOptionLabel={(option) => option}
        onChange={this.valueChange}
        renderInput={(params) => <TextField {...params} label="Select expiration" margin="normal" />}
      />
    )
  }
Example #4
Source File: search.jsx    From GraphVega with MIT License 6 votes vote down vote up
render() {
    return (
      <Autocomplete
        loading={this.state.loading}
        options={this.state.options}
        renderOption={(option, { selected }) => (
          <>
            {option.description}&nbsp;
            <div className="text-secondary">({option.symbol})</div>
          </>
        )}
        getOptionLabel={(option) => option.description}
        getOptionSelected={(option, value) =>
          option.description === value.description
        }
        onChange={this.valueChange}
        onInputChange={this.handleInputValueChange}
        filterOptions={(x) => x}
        renderInput={(params) => (
          <TextField
            {...params}
            label="Search by Company Name or (Symbol)"
            autoFocus={true}
            InputProps={{
              ...params.InputProps,
              endAdornment: (
                <React.Fragment>
                  {this.state.loading ? (
                    <CircularProgress size="1.5rem" />
                  ) : null}
                  {params.InputProps.endAdornment}
                </React.Fragment>
              ),
            }}
          />
        )}
      />
    );
  }
Example #5
Source File: FolioHeader.jsx    From archeage-tools with The Unlicense 5 votes vote down vote up
render() {
    const { open, loading, searchType, options } = this.state;
    const { items, mobile } = this.props;

    return (
      <AppBar position="static" className="section folio-header">
        <Toolbar>
          {!mobile &&
          <Typography variant="h5" className="title-text">Folio</Typography>}
          <Autocomplete
            open={open}
            onOpen={() => this.setOpen(true)}
            onClose={() => this.setOpen(false)}
            onChange={this.handleSearch}
            loading={loading}
            options={options}
            getOptionLabel={option => option.name || option}
            filterOptions={(options) => options}
            classes={{
              noOptions: 'folio-no-option',
            }}
            renderOption={option => (
              <div className="item-result" key={option.id}>
                <Item id={option.id} inline />
                {items[option.id]
                  ? <Typography variant="body2">{items[option.id].name}</Typography>
                  : <Skeleton variant="text" />}
              </div>
            )}
            freeSolo
            onInputChange={(e, value) => {
              this._handleQuery(value);
            }}
            renderInput={params => (
              <TextField
                {...params}
                label={`Search by ${searchTypes.find(type => type.value === searchType).label}`}
                fullWidth
                variant="standard"
                size="small"
                margin="none"
                InputProps={{
                  ...params.InputProps,
                  endAdornment: (
                    <>
                      {loading ? <CircularProgress color="inherit" size={20} /> : null}
                      {params.InputProps.endAdornment}
                    </>
                  ),
                }}
                InputLabelProps={{
                  ...params.InputLabelProps,
                }}
              />
            )}
          />
          <RadioGroup name="search-type" value={searchType} onChange={this.handleTypeChange} row={!mobile}>
            {searchTypes.map(searchType => (
              <FormControlLabel
                control={<Radio size="small" color="primary" />}
                {...searchType}
                key={searchType.value}
              />
            ))}
          </RadioGroup>
        </Toolbar>
      </AppBar>
    );
  }
Example #6
Source File: AnnounceMessage.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
AnnounceMessageForm = ({ setToggleAnnounceMessage }) => {
  const { orgList } = useContext(AppContext);
  const {
    setErrorMessage,
    user,
    regions,
    postBulkMessageSend,
    setThreads,
  } = useContext(MessagingContext);
  const { form, sendButton } = useStyles();
  const [organization, setOrganization] = useState({});
  const [inputValueOrg, setInputValueOrg] = useState('');
  const [region, setRegion] = useState({});
  const [inputValueRegion, setInputValueRegion] = useState('');
  const [errors, setErrors] = useState(null);

  const [values, setValues] = useState({
    title: '',
    message: '',
    videoLink: '',
  });

  const handleChange = (e) => {
    setErrors(null);
    const { name, value } = e.target;
    setValues({
      ...values,
      [name]: `${value}`,
    });
  };

  const validateAnnouncement = (payload) => {
    const errors = {};

    if (!payload.subject) {
      errors.subject = 'Please enter a subject for your announcement';
    }

    if (payload.body.length === 0 || !/\w/g.test(payload.body.trim())) {
      errors.body = 'Please enter a message';
    }
    const videoUrl = /^((?:https?:)?\/\/)?.*/;

    if (payload.video_link && !videoUrl.test(payload.video_link.trim())) {
      errors.video_link = 'Please enter a valid video link';
    }

    if (
      (!payload.region_id && !payload.organization_id) ||
      (payload.region_id && payload.organization_id)
    ) {
      errors.recipient = 'Please select an organization or region';
    }
    return errors;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    const payload = {
      author_handle: user.userName,
      subject: values.title,
      type: 'announce',
      body: values.message,
    };

    if (values?.videoLink) {
      payload['video_link'] = values.videoLink;
    }

    if (region?.id) {
      payload['region_id'] = region.id;
    }

    if (organization?.id) {
      payload['organization_id'] = organization.stakeholder_uuid;
    }

    const errs = validateAnnouncement(payload);

    try {
      const errorsFound = Object.keys(errs).length > 0;
      if (errorsFound) {
        setErrors(errs);
      } else {
        const res = await postBulkMessageSend(payload);

        setErrorMessage('');
        if (res.error) {
          setErrorMessage(
            `Sorry, something went wrong and we couldn't create the announcement: ${res.message}`
          );
        } else {
          // close the drawer
          setValues({
            title: '',
            message: '',
            videoLink: '',
          });
          setOrganization('');
          setRegion('');
          setToggleAnnounceMessage(false);

          const organization = orgList.find(
            (org) => org.stakeholder_uuid === payload.organization_id
          );
          const region = regions.find(
            (region) => region.id === payload.region_id
          );

          const newAnnouncement = {
            id: null,
            type: 'announce',
            parent_message_id: null,
            from: payload.author_handle,
            to: null,
            recipient_organization_id: payload.organization_id || null,
            recipient_region_id: payload.region_id || null,
            subject: payload.subject,
            body: payload.body,
            composed_at: new Date().toISOString(),
            video_link: null,
            survey_response: null,
            survey: null,
            bulk_message_recipients: [
              {
                organization: organization?.name,
                region: region?.name,
              },
            ],
          };
          log.debug('...update threads w/ new announcement');
          // update the full set of threads
          setThreads((prev) => [
            {
              username: `${newAnnouncement.id}`,
              messages: [newAnnouncement],
              avatar: '',
            },
            ...prev,
          ]);
        }
      }
    } catch (err) {
      console.log(err);
    }
  };

  return (
    <form className={form} onSubmit={handleSubmit}>
      {errors?.subject && (
        <Typography
          style={{ color: 'red', fontWeight: 'bold', margin: '20px 10px 0px' }}
        >
          {errors.subject}
        </Typography>
      )}
      <GSInputLabel text="Announce: Title" />
      <TextField
        fullWidth
        label="Title"
        name="title"
        value={values.title}
        onChange={handleChange}
        required
      />
      {errors?.body && (
        <Typography
          style={{ color: 'red', fontWeight: 'bold', margin: '20px 10px 0px' }}
        >
          {errors.body}
        </Typography>
      )}
      <GSInputLabel text={'Message'} />
      <TextField
        multiline
        rows={5}
        name="message"
        value={values.message}
        onChange={handleChange}
        label="Write your message here ..."
        required
      />
      {errors?.video_link && (
        <Typography
          style={{ color: 'red', fontWeight: 'bold', margin: '20px 10px 0px' }}
        >
          {errors.video_link}
        </Typography>
      )}
      <GSInputLabel text={'Add a Video Link'} />
      <TextField
        name="videoLink"
        value={values.videoLink}
        onChange={handleChange}
        label="Add a video link, e.g., YouTube URL"
      />
      {errors?.recipient && (
        <Typography
          style={{ color: 'red', fontWeight: 'bold', margin: '20px 10px 0px' }}
        >
          {errors.recipient}
        </Typography>
      )}
      <GSInputLabel
        id="select-label"
        text={'Target Audience by Organization'}
      />
      <Autocomplete
        name="organization"
        selectOnFocus
        handleHomeEndKeys
        options={orgList}
        getOptionLabel={(option) => option.name || ''}
        value={organization}
        onChange={(e, val) => setOrganization(val)}
        inputValue={inputValueOrg}
        getOptionSelected={(option, value) => option.id === value.id}
        onInputChange={(e, val) => {
          setErrors(null);
          setInputValueOrg(val);
        }}
        id="controllable-states-demo"
        freeSolo
        sx={{ width: 300 }}
        renderInput={(params) => (
          <TextField {...params} label="Select Organization" />
        )}
      />
      <GSInputLabel id="select-reg-label" text={'Target Audience by Region'} />
      <Autocomplete
        name="region"
        selectOnFocus
        handleHomeEndKeys
        value={region}
        onChange={(e, value) => setRegion(value)}
        options={regions}
        getOptionLabel={(option) => option.name || ''}
        inputValue={inputValueRegion}
        getOptionSelected={(option, value) => option.id === value.id}
        onInputChange={(e, val) => {
          setErrors(null);
          setInputValueRegion(val);
        }}
        id="controllable-states-demo"
        freeSolo
        sx={{ width: 300 }}
        renderInput={(params) => (
          <TextField {...params} label="Select Region" />
        )}
      />
      <Button disabled={!!errors} className={sendButton} type="submit">
        Send Message
      </Button>
    </form>
  );
}
Example #7
Source File: NewMessage.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
NewMessage = ({ openModal, handleClose, setMessageRecipient }) => {
  const { box, formContent, header, button } = useStyles();
  const {
    setErrorMessage,
    user,
    authors,
    setThreads,
    postMessageSend,
  } = useContext(MessagingContext);
  const [messageContent, setMessageContent] = useState('');
  const [recipient, setRecipient] = useState('');
  const [inputValue, setInputValue] = useState('');
  const [errors, setErrors] = useState(null);

  useEffect(() => {
    if (openModal === false) {
      setMessageContent('');
      setRecipient('');
    }
  }, [openModal]);

  useEffect(() => {
    // set an error message right away if there are no authors
    if (authors.length === 0) {
      setErrors('Sorry, no accounts were found.');
    }
  }, [authors]);

  const handleChange = (e) => {
    // don't remove the error if it's not a user mistake, like there aren't any authors
    if (authors.length > 0) {
      setErrors(null);
    }
    const { name, value } = e.target;
    name === 'body'
      ? setMessageContent(value)
      : setRecipient(e.target.textContent);
  };

  const validateMessage = (payload) => {
    const errors = {};

    if (payload.body.length === 0 || !/\w/g.test(payload.body.trim())) {
      errors.body = 'Please enter a message';
    }

    if (!payload.recipient_handle) {
      errors.recipient = 'Please select a recipient';
    }

    if (authors.length === 0) {
      errors.accounts = 'Sorry, no accounts were found.';
    }

    return errors;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    const messagePayload = {
      author_handle: user.userName,
      recipient_handle: recipient,
      type: 'message',
      body: messageContent,
    };

    const errs = validateMessage(messagePayload);

    const errorsFound = Object.keys(errs).length > 0;
    if (errorsFound) {
      setErrors(errs);
    } else {
      const res = await postMessageSend(messagePayload);

      if (res.error) {
        setErrorMessage(res.message);
      } else {
        const newMessage = {
          parent_message_id: null,
          body: messageContent,
          composed_at: new Date().toISOString(),
          from: user.userName,
          id: uuid(),
          recipient_organization_id: null,
          recipient_region_id: null,
          survey: null,
          to: recipient,
          type: 'message',
          video_link: null,
        };

        log.debug('...update threads after postMessageSend');
        // update the full set of threads
        setThreads((prev) =>
          [...prev, { userName: recipient, messages: [newMessage] }].sort(
            (a, b) =>
              new Date(b?.messages?.at(-1).composed_at) -
              new Date(a?.messages?.at(-1).composed_at)
          )
        );
      }

      setMessageRecipient(recipient);

      handleClose();
    }
  };

  return (
    <Modal
      open={openModal}
      onClose={handleClose}
      aria-labelledby="modal-modal-title"
      aria-describedby="modal-modal-description"
    >
      <Box className={box}>
        <form className={formContent} onSubmit={handleSubmit}>
          <Box className={header} my={1}>
            <Typography variant="h3">Send New Message</Typography>
          </Box>
          {errors?.accounts && (
            <Typography
              style={{
                color: 'red',
                fontWeight: 'bold',
                margin: '20px 10px 0px',
              }}
            >
              {errors.accounts}
            </Typography>
          )}
          <FormControl>
            {errors?.recipient && (
              <Typography
                style={{
                  color: 'red',
                  fontWeight: 'bold',
                  margin: '20px 10px 0px',
                }}
              >
                {errors.recipient}
              </Typography>
            )}
            <GSInputLabel text="Choose the Message Recipient" />
            <Autocomplete
              name="to"
              selectOnFocus
              clearOnBlur
              handleHomeEndKeys
              value={recipient}
              onChange={handleChange}
              options={
                authors.length
                  ? authors.map((author) => author.handle || '').sort()
                  : []
              }
              inputValue={inputValue}
              getOptionSelected={(option, value) => option === value}
              onInputChange={(e, val) => setInputValue(val)}
              id="controllable-states-demo"
              freeSolo
              sx={{ width: 300 }}
              renderInput={(params) => (
                <TextField {...params} label="Message Recipient" />
              )}
            />
          </FormControl>
          <FormControl>
            {errors?.message && (
              <Typography
                style={{
                  color: 'red',
                  fontWeight: 'bold',
                  margin: '20px 10px 0px',
                }}
              >
                {errors.message}
              </Typography>
            )}
            <GSInputLabel text="Message" />
            <TextField
              multiline
              placeholder="Write your message here ..."
              name="body"
              value={messageContent}
              onChange={handleChange}
            />
          </FormControl>
          <Button
            type="submit"
            size="large"
            className={button}
            disabled={!!errors}
          >
            Send Message
          </Button>
        </form>
      </Box>
    </Modal>
  );
}
Example #8
Source File: Survey.js    From treetracker-admin-client with GNU Affero General Public License v3.0 4 votes vote down vote up
SurveyForm = ({ setToggleSurvey }) => {
  const { form, submitButton, input } = useStyles();
  const {
    setErrorMessage,
    user,
    regions,
    postBulkMessageSend,
    setThreads,
  } = useContext(MessagingContext);
  const { orgList } = useContext(AppContext);
  const [title, setTitle] = useState('');
  const [questionOne, setQuestionOne] = useState({
    prompt: '',
    choiceOne: '',
    choiceTwo: '',
    choiceThree: '',
  });
  const [questionTwo, setQuestionTwo] = useState({
    prompt: '',
    choiceOne: '',
    choiceTwo: '',
    choiceThree: '',
  });
  const [questionThree, setQuestionThree] = useState({
    prompt: '',
    choiceOne: '',
    choiceTwo: '',
    choiceThree: '',
  });
  const [errors, setErrors] = useState(null);

  // * Both values needed for organization/region autocompletes
  const [organization, setOrganization] = useState({});
  const [inputValueOrg, setInputValueOrg] = useState('');
  const [region, setRegion] = useState({});
  const [inputValueRegion, setInputValueRegion] = useState('');

  const handleChange = (e, question) => {
    setErrors(null);
    const { name, value } = e.target;
    if (question === 'questionOne') {
      setQuestionOne({
        ...questionOne,
        [name]: value,
      });
    } else if (question === 'questionTwo') {
      setQuestionTwo({
        ...questionTwo,
        [name]: value,
      });
    } else if (question === 'questionThree') {
      setQuestionThree({
        ...questionThree,
        [name]: value,
      });
    } else if (name === 'title') {
      setTitle(value);
    }
  };

  const validateSurvey = (payload) => {
    const errors = {};

    if (!payload.subject && payload.survey.title.length <= 1) {
      errors.title = 'Please enter a title for your survey';
    }

    if (payload.survey.questions.length === 0) {
      errors.questions = 'Please enter at least one question';
    } else {
      payload.survey.questions.forEach((question) => {
        if (!question.prompt) {
          errors.questions = 'Please enter a prompt for each question';
        }

        if (
          question.choices.length < 3 ||
          question.choices.some((choice) => choice === '')
        ) {
          errors.questions = 'Please enter 3 choices for each question';
        }
      });
    }

    if (
      (!payload.region_id && !payload.organization_id) ||
      (payload.region_id && payload.organization_id)
    ) {
      errors.recipient = 'Please select an organization or region';
    }
    return errors;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    const allQuestions = { questionOne, questionTwo, questionThree };
    const payload = {
      author_handle: user.userName,
      subject: title,
      type: 'survey',
      body: 'Survey',
      survey: {
        title: title,
        questions: [],
      },
    };

    if (region?.id) {
      payload['region_id'] = region.id;
    }
    if (organization?.id) {
      payload['organization_id'] = organization.stakeholder_uuid;
    }

    Object.values(allQuestions).forEach((question) => {
      const { prompt, choiceOne, choiceTwo, choiceThree } = question;
      if (prompt.length > 1) {
        payload.survey.questions.push({
          prompt,
          choices: [choiceOne, choiceTwo, choiceThree],
        });
      }
    });

    const errs = validateSurvey(payload);

    try {
      const errorsFound = Object.keys(errs).length > 0;
      if (errorsFound) {
        setErrors(errs);
      } else {
        const res = await postBulkMessageSend(payload);

        setErrorMessage('');
        if (res.error) {
          setErrorMessage(
            `Sorry, something went wrong and we couldn't create the survey: ${res.message}`
          );
        } else {
          // reset and hide the survey drawer
          setQuestionOne({
            prompt: '',
            choiceOne: '',
            choiceTwo: '',
            choiceThree: '',
          });
          setQuestionTwo({
            prompt: '',
            choiceOne: '',
            choiceTwo: '',
            choiceThree: '',
          });
          setQuestionThree({
            prompt: '',
            choiceOne: '',
            choiceTwo: '',
            choiceThree: '',
          });
          setOrganization('');
          setRegion('');
          setTitle('');
          setToggleSurvey(false);

          const newSurvey = {
            id: uuid(),
            type: 'survey',
            parent_message_id: null,
            from: payload.author_handle,
            to: null,
            recipient_organization_id: payload.organization_id || null,
            recipient_region_id: payload.region_id || null,
            subject: payload.subject,
            body: null,
            composed_at: new Date().toISOString(),
            video_link: null,
            survey_response: null,
            survey: payload.survey,
          };

          log.debug('...update threads w/ new survey');

          // update state with with the new survey
          setThreads((prev) => [
            {
              username: `${newSurvey.id}`,
              messages: [newSurvey],
              avatar: '',
            },
            ...prev,
          ]);
        }
      }
    } catch (err) {
      console.log(err);
    }
  };

  return (
    <form className={form} onSubmit={handleSubmit}>
      <GSInputLabel text="Survey Title" />
      <TextField
        className={input}
        fullWidth
        label="Survey Title"
        name="title"
        value={title}
        onChange={handleChange}
        {...(errors?.title && { error: true })}
      />
      {errors?.questions && (
        <Typography
          style={{
            color: 'red',
            fontWeight: 'bold',
            margin: '20px 10px 0px',
          }}
        >
          {errors.questions}
        </Typography>
      )}
      {['One', 'Two', 'Three'].map((num) => (
        <div key={num}>
          <GSInputLabel text={`Survey Question ${num}`} />
          <TextField
            className={input}
            fullWidth
            label="Write your question: "
            name="prompt"
            value={`question${num}`['prompt']}
            onChange={(e) => handleChange(e, `question${num}`)}
            {...(errors?.questions && { error: true })}
          />
          <GSInputLabel text={`Question ${num} Answer Options`} />
          <TextField
            className={input}
            fullWidth
            label="A: "
            name="choiceOne"
            value={`question${num}`['choiceOne']}
            onChange={(e) => handleChange(e, `question${num}`)}
            {...(errors?.questions && { error: true })}
          />
          <TextField
            className={input}
            fullWidth
            label="B: "
            name="choiceTwo"
            value={`question${num}`['choiceTwo']}
            onChange={(e) => handleChange(e, `question${num}`)}
            {...(errors?.questions && { error: true })}
          />
          <TextField
            className={input}
            fullWidth
            label="C: "
            name="choiceThree"
            value={`question${num}`['choiceThree']}
            onChange={(e) => handleChange(e, `question${num}`)}
            {...(errors?.questions && { error: true })}
          />
        </div>
      ))}
      <div>
        {errors?.recipient && (
          <Typography
            style={{
              color: 'red',
              fontWeight: 'bold',
              margin: '20px 10px 0px',
            }}
          >
            {errors.recipient}
          </Typography>
        )}
        <FormControl fullWidth {...(errors?.recipient && { error: true })}>
          <GSInputLabel
            id="select-label"
            text={'Target Audience by Organization'}
          />
          <Autocomplete
            name="organization"
            selectOnFocus
            handleHomeEndKeys
            options={orgList}
            getOptionLabel={(option) => option.name || ''}
            value={organization}
            onChange={(e, val) => setOrganization(val)}
            inputValue={inputValueOrg}
            getOptionSelected={(option, value) => option.id === value.id}
            onInputChange={(e, val) => {
              setErrors(null);
              setInputValueOrg(val);
            }}
            id="controllable-states-demo"
            freeSolo
            sx={{ width: 300 }}
            renderInput={(params) => (
              <TextField
                {...params}
                label="Select Organization"
                {...(errors?.recipient && { error: true })}
              />
            )}
          />
        </FormControl>
        <FormControl fullWidth {...(errors?.recipient && { error: true })}>
          <GSInputLabel
            id="select-reg-label"
            text={'Target Audience by Region'}
          />
          <Autocomplete
            name="region"
            selectOnFocus
            handleHomeEndKeys
            value={region}
            onChange={(e, value) => setRegion(value)}
            options={regions}
            getOptionLabel={(option) => option.name || ''}
            inputValue={inputValueRegion}
            getOptionSelected={(option, value) => option.id === value.id}
            onInputChange={(e, val) => {
              setErrors(null);
              setInputValueRegion(val);
            }}
            id="controllable-states-demo"
            freeSolo
            sx={{ width: 300 }}
            renderInput={(params) => (
              <TextField
                {...params}
                label="Select Region"
                {...(errors?.recipient && { error: true })}
              />
            )}
          />
        </FormControl>
      </div>
      <Button
        disabled={!!errors}
        type="submit"
        size="large"
        className={submitButton}
      >
        Submit
      </Button>
    </form>
  );
}
Example #9
Source File: Crops.jsx    From archeage-tools with The Unlicense 4 votes vote down vote up
render() {
    const { mobile, crops, removeCrop, items, climates } = this.props;
    const { dd, hh, mm, ss, climate, crop, note, timer, seedbed, errors } = this.state;

    const cropCustom = CROP_CUSTOM[crop.id];

    setTitle('My Farm Timers');

    return (
      <div className={cn('tool-container', { mobile })}>
        <Paper className="section">
          <AppBar position="static">
            <Toolbar>
              <Typography variant="h5" className="title-text">My Farm Timers</Typography>
            </Toolbar>
          </AppBar>
          <div className="crops-container">
            <Autocomplete
              className="crop-select"
              autoHighlight
              disableClearable
              blurOnSelect
              size="small"
              loading={!items.length}
              options={items}
              onChange={this.handleSelectCrop}
              value={crop}
              getOptionLabel={option => option.name || ''}
              renderOption={option => (
                <div className="item-result" key={option.id}>
                  <Item id={option.id} inline />
                  <Typography variant="body2">{option.name}</Typography>
                </div>
              )}
              groupBy={option => option.group}
              renderInput={params => (
                <FormControl error={hasProperty(errors, 'crop')}>
                  <TextField
                    {...params}
                    label={`Find a crop, tree, or livestock`}
                    variant="standard"
                    size="medium"
                    InputProps={{
                      ...params.InputProps,
                      endAdornment: (
                        <>
                          {params.InputProps.endAdornment}
                        </>
                      ),
                    }}
                    InputLabelProps={{
                      ...params.InputLabelProps,
                    }}
                  />
                  {errors.crop && <FormHelperText>{errors.crop}</FormHelperText>}
                </FormControl>
              )}
            />
            <FormControl component="fieldset">
              <FormLabel>Timer</FormLabel>
              <RadioGroup
                name="timer-type"
                value={timer}
                onChange={this.handleTimerChange}
              >
                <FormControlLabel
                  value={TIMER_TYPE.MATURES}
                  control={<Radio size="small" />}
                  label="Matures"
                  disabled={cropCustom && !cropCustom.types.includes(TIMER_TYPE.MATURES)}
                />
                <FormControlLabel
                  value={TIMER_TYPE.HARVEST}
                  control={<Radio size="small" />}
                  label="Harvest"
                  disabled={(!crop.description || !crop.description.match(HARVEST_REGEX)) && !(cropCustom && cropCustom.types.includes(TIMER_TYPE.HARVEST))}
                />
              </RadioGroup>
            </FormControl>
            <FormControl className="select-group" error={hasProperty(errors, 'climate')}>
              <InputLabel className="group-label" shrink>Climate(s)</InputLabel>
              <ButtonGroup color="secondary">
                {Object.values(climates).map(c => (
                  <Tooltip title={c.name} key={`climate-${c.id}`}>
                    <Button
                      variant={climate.includes(c.name) && !seedbed ? 'contained' : 'outlined'}
                      className={cn({ selected: climate.includes(c.name) })}
                      onClick={(e) => this.handleSelectClimate(e, c.name)}
                      disabled={seedbed}
                    >
                      <span className={cn('climate-icon small', c.name)} />
                    </Button>
                  </Tooltip>
                ))}
              </ButtonGroup>
              {errors.climate && <FormHelperText>{errors.climate}</FormHelperText>}
              <FormControlLabel
                control={<Checkbox size="small" />}
                label="Seedbed?"
                disabled={crop.type !== 'Seed' || crop.name.includes('Bundle')}
                checked={seedbed}
                onChange={this.handleSeedbedChange}
              />
            </FormControl>
            <FormControl className="ts-select">
              <InputLabel shrink>Time Remaining</InputLabel>
              <div className="multi-input">
                <Input
                  id="dd"
                  placeholder="0"
                  endAdornment="d"
                  inputProps={{
                    maxLength: 1,
                    ref: this.dd,
                  }}
                  value={dd}
                  onChange={this.handleTimeChange('dd')}
                  onKeyPress={this.checkEnter}
                />
                <Input
                  id="hh"
                  placeholder="0"
                  endAdornment="h"
                  inputProps={{
                    maxLength: 2,
                    ref: this.hh,
                  }}
                  value={hh}
                  onChange={this.handleTimeChange('hh')}
                  onKeyPress={this.checkEnter}
                />
                <Input
                  id="mm"
                  placeholder="0"
                  endAdornment="m"
                  inputProps={{
                    maxLength: 2,
                    ref: this.mm,
                  }}
                  value={mm}
                  onChange={this.handleTimeChange('mm')}
                  onKeyPress={this.checkEnter}
                />
                <Input
                  id="ss"
                  placeholder="0"
                  endAdornment="s"
                  inputProps={{
                    maxLength: 2,
                    ref: this.ss,
                  }}
                  value={ss}
                  onChange={this.handleTimeChange('ss')}
                  onKeyPress={this.checkEnter}
                />
              </div>
              <Typography variant="overline" style={{ fontSize: 10 }}>Leave blank for default times.</Typography>
            </FormControl>
            <TextField
              className="ts-select"
              label="Note (optional)"
              value={note}
              onChange={this.changeNote}
              onKeyPress={this.checkEnter}
            />
            <FormControl className="ts-track-button">
              <Button color="primary" variant="contained" onClick={this.addCrop}>Track</Button>
            </FormControl>
          </div>
        </Paper>
        <Paper className="section">
          <AppBar position="static">
            <Toolbar variant="dense">
              <Typography variant="subtitle1" className="title-text">Timers</Typography>
            </Toolbar>
          </AppBar>
          <Table size="small">
            <TableBody>
              {crops.map((crop, index) => (
                <CropTimer
                  {...crop}
                  key={`crop-${index}`}
                  onDelete={() => removeCrop(index)}
                  onRestart={() => this.reharvestCrop(index, crop)}
                  onMark={this.setMark(index)}
                />
              ))}
            </TableBody>
          </Table>
        </Paper>
        <AdContainer type="horizontal" />
      </div>
    );
  }
Example #10
Source File: Skills.jsx    From archeage-tools with The Unlicense 4 votes vote down vote up
render() {
    const { skillsets } = this.state;
    const { mobile, findClassName, classes, skillsets: skillsetData } = this.props;

    let className;
    const selectedSkillsets = skillsets.map(sks => sks.id);
    if (skillsets.every(sks => Boolean(sks.id))) {
      className = findClassName(selectedSkillsets);
    }

    const spentPoints = this.getSpentPoints();
    const remainingPoints = MAX_POINTS - spentPoints;
    const skillsetPoints = this.getTreePoints();

    if (className) {
      setTitle(`${className} Build (${skillsetPoints.join('/')})`);
    } else {
      const skillsetNames = selectedSkillsets.filter(id => Boolean(id)).map(id => skillsetData[id].name);
      if (skillsetNames.length > 0) {
        setTitle(`${skillsetNames.join('/')} Build (${skillsetPoints.splice(0, skillsetNames.length).join('/')})`);
      } else {
        setTitle('Skill Calculator');
      }
    }

    return (
      <div className="skills-container">
        <div className="skills-header">
          <Paper className="section">
            <AppBar position="static">
              <Toolbar>
                <Typography variant="h5">
                  Skill Builder:
                </Typography>
                <Autocomplete
                  className="title-text class-select color-white"
                  autoHighlight
                  disableClearable
                  blurOnSelect
                  size="small"
                  loading={!objectHasProperties(classes)}
                  options={classes}
                  onChange={this.handleSelectClass}
                  value={{ name: className, skillsetIds: selectedSkillsets }}
                  getOptionLabel={option => option.name || ''}
                  renderOption={option => (
                    <div className="class-result" key={`class-${option.name}`}>
                      <div className="skillset-icons">
                        {option.skillsetIds.sort((a, b) => a - b).map(id => (
                          <span className="skillset-icon" data-id={id} key={`${option.name}-${id}`} />
                        ))}
                      </div>
                      <Typography variant="body2">{option.name}</Typography>
                    </div>
                  )}
                  renderInput={params => (
                    <TextField
                      {...params}
                      label={`Find a class`}
                      variant="standard"
                      size="medium"
                      margin="none"
                      InputProps={{
                        ...params.InputProps,
                        endAdornment: (
                          <>
                            {params.InputProps.endAdornment}
                          </>
                        ),
                      }}
                      InputLabelProps={{
                        ...params.InputLabelProps,
                      }}
                    />
                  )}
                />
                <Typography variant="subtitle2">{spentPoints}/{MAX_POINTS}</Typography>
                <Tooltip title="Reset All Trees">
                  <IconButton color="inherit" aria-label="Reset" onClick={this.resetAllTrees}>
                    <ReplayIcon />
                  </IconButton>
                </Tooltip>
              </Toolbar>
            </AppBar>
          </Paper>
        </div>
        <div className={cn('section', 'skill-trees', { mobile })}>
          {[0, 1, 2].map(treeId =>
            <SkillTree
              treeId={treeId}
              key={`tree-${treeId}`}
              setSkillTree={this.setSkillTree}
              setSkill={this.setSkill}
              setAncestral={this.setAncestral}
              resetSkillTree={this.resetSkillTree}
              treeData={skillsets[treeId]}
              remainingPoints={remainingPoints}
              selectedSkillset={selectedSkillsets}
            />,
          )}
        </div>
        <AdContainer type="horizontal" />
      </div>
    );
  }
Example #11
Source File: Taxes.jsx    From archeage-tools with The Unlicense 4 votes vote down vote up
// eslint-disable-next-line complexity
  render() {
    const { openDialog, calculateLabor, mobile, price, buildings, createBuilding, characters } = this.props;
    const { hostile, options, building, character, editId, editOpen, selectedOnly } = this.state;
    const characterList = characters.length > 0 ? characters : ['Character 1'];

    setTitle('Tax Calculator');

    const properties = buildings.map(({ itemId, hostile, character }, index) => ({
      ...createBuilding(itemId),
      hostile,
      index,
      character,
    }));
    const characterProperties = properties.filter(filterByCharacter(character));
    const heavyTaxProperties = characterList.map((_, i) => countAll(properties.filter(filterByCharacter(i)).map(p => p.exempt
      ? 0 : 1)));

    const heavyTaxRate = characterList.map((_, i) => HEAVY_TAX_RATE[Math.min(heavyTaxProperties[i] || 0, 8)]);
    const taxesPerWeek = characterList.map((_, i) => this.calculateTaxes(properties.filter(filterByCharacter(i)), heavyTaxRate[i]));

    const laborCost = characterList.map((_, i) => Math.ceil(taxesPerWeek[i] / 5) * (calculateLabor(300, CONSTRUCTION)));

    // pending property
    const pendingProperty = building.itemId ? ({ ...createBuilding(building.itemId), hostile }) : null;
    let placeCost = 0;
    let placeIncrease = 0;
    if (pendingProperty) {
      const { baseTax, deposit, hostile, exempt } = pendingProperty;
      const newHeavyProperties = heavyTaxProperties[character] + (exempt ? 0 : 1);
      const newHeavyRate = HEAVY_TAX_RATE[Math.min(newHeavyProperties, 8)];
      const heavyTaxFee = !exempt ? Math.round(newHeavyRate * baseTax) : 0;
      const hostileFee = hostile ? baseTax * HOSTILE_FACTION_TAX : 0;
      const taxRate = baseTax + heavyTaxFee + hostileFee;
      const newTaxes = this.calculateTaxes([...characterProperties, pendingProperty], newHeavyRate);
      placeIncrease = newTaxes - taxesPerWeek[character];
      placeCost = taxRate + deposit;
    }

    const taxPrice = (
      <>
        <TableCell colSpan={mobile ? 2 : 1}>
          <Item id={ITEM.TAX_CERTIFICATE} inline /> Price:
        </TableCell>
        <TableCell align="right" colSpan={mobile ? 2 : 1}>
          <ItemPrice itemId={ITEM.TAX_CERTIFICATE} unitSize={1} />
        </TableCell>
      </>
    );

    const taxSilverPerLabor = (
      <>
        <TableCell colSpan={mobile ? 2 : 1}>
          <Tooltip title="Silver per labor">
            <span>
              <span className="dropdown-icon silver" /> per Labor:
            </span>
          </Tooltip>
        </TableCell>
        <TableCell align="right" colSpan={mobile ? 2 : 1}>
          <Currency
            type={CURRENCY.COIN}
            count={(price ? price - 0.0046 : 0) * 5 / calculateLabor(300, CONSTRUCTION) * 10000}
          />
        </TableCell>
      </>
    );

    return (
      <div className={cn('tool-container', { mobile })}>
        <Paper className="section">
          <AppBar position="static">
            <Toolbar>
              <Typography variant="h5" className="title-text">Tax Calculator</Typography>
              <Tooltip title="Configure Proficiency">
                <IconButton onClick={() => openDialog(DIALOG_MY_GAME, PROFICIENCIES)} color="inherit">
                  <ListAltIcon />
                </IconButton>
              </Tooltip>
            </Toolbar>
          </AppBar>
          <div className="calculator-box">
            <div className="calculator-totals">
              <Autocomplete
                className="building-select"
                autoHighlight
                disableClearable
                blurOnSelect
                size="small"
                loading={!options.length}
                options={options}
                onChange={this.handleSelectBuilding}
                value={building}
                getOptionLabel={option => option.name || ''}
                renderOption={option => (
                  <div className="item-result" key={option.id}>
                    <Item id={option.itemId} inline />
                    <Typography variant="body2">{option.name}</Typography>
                  </div>
                )}
                groupBy={option => option.group}
                renderInput={params => (
                  <FormControl>
                    <TextField
                      {...params}
                      label={`Find a building`}
                      variant="standard"
                      size="medium"
                      InputProps={{
                        ...params.InputProps,
                        endAdornment: (
                          <>
                            {params.InputProps.endAdornment}
                          </>
                        ),
                      }}
                      InputLabelProps={{
                        ...params.InputLabelProps,
                      }}
                    />
                  </FormControl>
                )}
              />
              <Table size="small" className="place-info">
                <TableBody>
                  <TableRow>
                    <TableCell>
                      <Item id={ITEM.TAX_CERTIFICATE} inline /> to Place:
                    </TableCell>
                    <TableCell align="right">
                      {placeCost}
                    </TableCell>
                  </TableRow>
                  <TableRow>
                    <TableCell>
                      Additional <Item id={ITEM.TAX_CERTIFICATE} inline /> per Week:
                    </TableCell>
                    <TableCell align="right">
                      {placeIncrease}
                    </TableCell>
                  </TableRow>
                </TableBody>
              </Table>
              <div className="form-options">
                <Tooltip title={
                  <>
                    <Typography style={{ textDecoration: 'underline' }}>Hostile Zones</Typography>
                    <Typography variant="body2">
                      Hostile zones are zones that are controlled by an enemy faction.<br />
                      Conflict zones are not considered hostile, but Growlgate Isle is considered hostile if you&apos;re
                      not a pirate.<br />
                      Placing property in a hostile zone will incur a hostile faction tax of
                      +{HOSTILE_FACTION_TAX * 100}%.
                    </Typography>
                  </>
                }
                >
                  <FormControlLabel
                    control={<Checkbox onChange={this.toggleHostile} checked={hostile} color="primary" />}
                    label="In Hostile Zone"
                  />
                </Tooltip>
                <Button
                  color="primary"
                  variant="contained"
                  disabled={!building.itemId}
                  onClick={this.addProperty}
                >
                  Add Property
                </Button>
              </div>
              <Table size="small" className="total-list" stickyHeader>
                <TableHead>
                  <TableRow>
                    <TableCell colSpan={2}>
                      Tax Totals
                    </TableCell>
                    <TableCell colSpan={mobile ? 2 : 4} align="right">
                      [
                      <Link
                        onClick={this.handleSelectedOnly(false)}
                        style={{ textDecoration: !selectedOnly ? 'underline' : 'none', cursor: 'pointer' }}
                        color="inherit"
                      >
                        All Characters
                      </Link>
                      &nbsp;|&nbsp;
                      <Link
                        onClick={this.handleSelectedOnly(true)}
                        style={{ textDecoration: selectedOnly ? 'underline' : 'none', cursor: 'pointer' }}
                        color="inherit"
                      >
                        Selected Character
                      </Link>]
                    </TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  <TableRow>
                    <TableCell>Properties:</TableCell>
                    <TableCell align="right">
                      {selectedOnly ? characterProperties.length : properties.length}
                      {((selectedOnly && heavyTaxProperties[character] !== characterProperties.length) || (!selectedOnly && countAll(Object.values(heavyTaxProperties)) !== properties.length)) &&
                      <Tooltip title="Heavy Tax Properties">
                        <span>&nbsp;<span className="hint">
                          ({selectedOnly ? (heavyTaxProperties[character] || 0)
                          : countAll(Object.values(heavyTaxProperties))})
                        </span></span>
                      </Tooltip>}
                    </TableCell>
                    <TableCell>
                      <Tooltip
                        title={
                          <Table size="small" stickyHeader>
                            <TableHead>
                              <TableRow>
                                <TableCell>
                                  Properties
                                </TableCell>
                                <TableCell align="right">
                                  Rate
                                </TableCell>
                              </TableRow>
                            </TableHead>
                            <TableBody>
                              {HEAVY_TAX_RATE.filter((_, i) => i > 0).map((rate, id) => (
                                <TableRow key={`rate-tip-${id}`}>
                                  <TableCell>
                                    {id + 1}{id + 2 === HEAVY_TAX_RATE.length && '+'}
                                  </TableCell>
                                  <TableCell align="right">
                                    +{rate * 100}%
                                  </TableCell>
                                </TableRow>
                              ))}
                            </TableBody>
                          </Table>
                        }
                      >
                        <span className="hint">Heavy Tax Rate:</span>
                      </Tooltip>
                    </TableCell>
                    <TableCell align="right">
                      <OptionalTooltip
                        title={!selectedOnly &&
                        <Table size="small" stickyHeader>
                          <TableHead>
                            <TableRow>
                              <TableCell>
                                Character
                              </TableCell>
                              <TableCell align="right">
                                Rate
                              </TableCell>
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {Object.entries(heavyTaxRate).map(([id, rate]) => (
                              <TableRow key={`rate-row-${id}`}>
                                <TableCell>
                                  {characterList[id]}
                                </TableCell>
                                <TableCell align="right">
                                  +{rate * 100}%
                                </TableCell>
                              </TableRow>
                            ))}
                          </TableBody>
                        </Table>}
                      >
                        <span>+{(selectedOnly ? heavyTaxRate[character]
                          : Object.values(heavyTaxRate).reduce((max, v) => v > max ? v : max, 0)) * 100}%</span>
                      </OptionalTooltip>
                    </TableCell>
                    {!mobile && taxPrice}
                  </TableRow>
                  <TableRow>
                    <TableCell><Item id={ITEM.TAX_CERTIFICATE} inline /> per Week:</TableCell>
                    <TableCell align="right">{selectedOnly ? taxesPerWeek[character]
                      : countAll(Object.values(taxesPerWeek))}</TableCell>
                    <TableCell>Labor per Week:</TableCell>
                    <TableCell align="right">{selectedOnly ? laborCost[character]
                      : countAll(Object.values(laborCost))}</TableCell>
                    {!mobile && taxSilverPerLabor}
                  </TableRow>
                  {mobile &&
                  <>
                    <TableRow>
                      {taxPrice}
                    </TableRow>
                    <TableRow>
                      {taxSilverPerLabor}
                    </TableRow>
                  </>}
                </TableBody>
              </Table>
            </div>
            {!mobile &&
            <AdContainer section={false} type="square" />}
          </div>
        </Paper>
        {mobile && <AdContainer type="feed" />}
        <Paper className="section">
          <AppBar position="static">
            <Toolbar variant="dense">
              <Tabs
                value={Math.min(character, characterList.length - 1)}
                onChange={this.setCharacter}
                variant="scrollable"
              >
                {characterList.map((name, id) => (
                  <Tab
                    key={`tax-character-${id}`}
                    value={id}
                    label={
                      <span>
                        {name}
                        <IconButton
                          color="inherit"
                          size="small"
                          onClick={(e) => {
                            e.stopPropagation();
                            this.handleEditCharacter(id);
                          }}
                          style={{ marginLeft: 12 }}
                        >
                          <EditIcon />
                        </IconButton>
                      </span>
                    }
                  />
                ))}
              </Tabs>
              <Tooltip title="Add Character">
                <span>
                <IconButton
                  onClick={() => this.handleEditCharacter(null)}
                  color="inherit"
                  disabled={characters.length >= MAX_CHARACTERS}
                >
                  <AddIcon />
                </IconButton>
                </span>
              </Tooltip>
            </Toolbar>
          </AppBar>
          {mobile
            ? <PropertyList
              calculateTax={this.calculateTax}
              properties={properties}
              heavyTaxProperties={heavyTaxProperties[character]}
              heavyTaxRate={heavyTaxRate[character]}
              character={character}
            />
            : <PropertyTable
              calculateTax={this.calculateTax}
              properties={properties}
              heavyTaxProperties={heavyTaxProperties[character]}
              heavyTaxRate={heavyTaxRate[character]}
              character={character}
            />}
        </Paper>
        <AdContainer type="horizontal" />
        <CharacterDialog
          characterId={editId}
          open={editOpen}
          onClose={this.handleEditClose}
        />
      </div>
    );
  }