* add default placeholder, remove focus on first load * fix some bugs re autofocus and mouse click to select * allow custom selected styles to be passed in * operate on objects with name property rather than plain strings * WIP main functionality in place * set default selections, allow a max to be placed on selections * switch help context * bug fixes to edit mode, static suggestions * make sure suggestion resumes when edit begins * cleanup and docs * update existing form test * add component tests * add more component test cases * refactor max selections flow, ensure default tag data only loads once * stop removing combobox properties now the input stays visible * add max selections test * refactor * make sure input refocus happens after blur event * update cypress tests * some small renames and doc changes * only fetch exact matches from added tags * fix test, update dark theme background * set a max height on the popover, and ensure options can be scrolled into view * woops - max height * Update app/javascript/article-form/components/TagsField.jsx Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com> * refactors * stop dropdown from flickering * use ButtonNew * remove redundant variant * nudge PR checks Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com>
137 lines
4.2 KiB
JavaScript
137 lines
4.2 KiB
JavaScript
import { h, Component } from 'preact';
|
|
import PropTypes from 'prop-types';
|
|
import linkState from 'linkstate';
|
|
import { Tags, DEFAULT_TAG_FORMAT } from '../shared/components/tags';
|
|
import { OrganizationPicker } from '../organization/OrganizationPicker';
|
|
import { Title } from './components/Title';
|
|
import { BodyMarkdown } from './components/BodyMarkdown';
|
|
import { Categories } from './components/Categories';
|
|
import { ExpireDate } from './components/ExpireDate';
|
|
|
|
export class ListingForm extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
const {
|
|
listing,
|
|
categoriesForDetails,
|
|
categoriesForSelect,
|
|
organizations: unparsedOrganizations,
|
|
} = this.props;
|
|
this.listing = JSON.parse(listing);
|
|
this.categoriesForDetails = JSON.parse(categoriesForDetails);
|
|
this.categoriesForSelect = JSON.parse(categoriesForSelect);
|
|
|
|
const organizations = JSON.parse(unparsedOrganizations);
|
|
|
|
this.url = window.location.href;
|
|
|
|
this.state = {
|
|
id: this.listing.id || null,
|
|
title: this.listing.title || '',
|
|
category: this.listing.category || '',
|
|
tagList: this.listing.cached_tag_list || '',
|
|
bodyMarkdown: this.listing.body_markdown || '',
|
|
categoriesForSelect: this.categoriesForSelect,
|
|
categoriesForDetails: this.categoriesForDetails,
|
|
organizations,
|
|
organizationId: null, // change this for /edit later
|
|
expireDate: this.listing.expires_at || '',
|
|
};
|
|
}
|
|
|
|
handleOrgIdChange = (e) => {
|
|
const organizationId = e.target.selectedOptions[0].value;
|
|
this.setState({ organizationId });
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
id,
|
|
title,
|
|
bodyMarkdown,
|
|
tagList,
|
|
category,
|
|
categoriesForDetails,
|
|
categoriesForSelect,
|
|
organizations,
|
|
organizationId,
|
|
expireDate,
|
|
} = this.state;
|
|
|
|
const selectOrg =
|
|
organizations && organizations.length > 0 ? (
|
|
<div className="crayons-field">
|
|
<label htmlFor="organizationId" className="crayons-field__label">
|
|
Post under an organization
|
|
</label>
|
|
<OrganizationPicker
|
|
name="listing[organization_id]"
|
|
id="listing_organization_id"
|
|
className="crayons-select m:max-w-50"
|
|
organizations={organizations}
|
|
organizationId={organizationId}
|
|
onToggle={this.handleOrgIdChange}
|
|
/>
|
|
<p className="crayons-field__description">
|
|
Posting on behalf of an organization spends the organization's
|
|
credits.
|
|
</p>
|
|
</div>
|
|
) : null;
|
|
|
|
if (id === null) {
|
|
return (
|
|
<div className="grid gap-6">
|
|
<Title defaultValue={title} onChange={linkState(this, 'title')} />
|
|
<BodyMarkdown
|
|
defaultValue={bodyMarkdown}
|
|
onChange={linkState(this, 'bodyMarkdown')}
|
|
/>
|
|
<Categories
|
|
categoriesForSelect={categoriesForSelect}
|
|
categoriesForDetails={categoriesForDetails}
|
|
onChange={linkState(this, 'category')}
|
|
category={category}
|
|
/>
|
|
<div className="relative">
|
|
<Tags
|
|
defaultValue={tagList}
|
|
category={category}
|
|
onInput={linkState(this, 'tagList')}
|
|
classPrefix="listingform"
|
|
fieldClassName="crayons-textfield"
|
|
maxTags={8}
|
|
autocomplete="off"
|
|
listing
|
|
pattern={DEFAULT_TAG_FORMAT}
|
|
/>
|
|
</div>
|
|
<ExpireDate
|
|
defaultValue={expireDate}
|
|
onChange={linkState(this, 'expireDate')}
|
|
/>
|
|
{selectOrg}
|
|
</div>
|
|
);
|
|
}
|
|
// WIP code for edit
|
|
return (
|
|
<div>
|
|
<Title defaultValue={title} onChange={linkState(this, 'title')} />
|
|
<BodyMarkdown
|
|
defaultValue={bodyMarkdown}
|
|
onChange={linkState(this, 'bodyMarkdown')}
|
|
/>
|
|
<Tags defaultValue={tagList} onInput={linkState(this, 'tagList')} />
|
|
{selectOrg}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
ListingForm.propTypes = {
|
|
listing: PropTypes.string.isRequired,
|
|
categoriesForDetails: PropTypes.string.isRequired,
|
|
categoriesForSelect: PropTypes.string.isRequired,
|
|
organizations: PropTypes.string.isRequired,
|
|
};
|