WiP on segments
This commit is contained in:
parent
6cc34136f5
commit
f3ff89c536
21 changed files with 945 additions and 352 deletions
|
@ -14,7 +14,8 @@ import { getFieldTypes } from './field-types';
|
|||
import interoperableErrors from '../../../../shared/interoperable-errors';
|
||||
import validators from '../../../../shared/validators';
|
||||
import slugify from 'slugify';
|
||||
import { parseDate, parseBirthday } from '../../../../shared/fields';
|
||||
import { parseDate, parseBirthday, DateFormat } from '../../../../shared/date';
|
||||
import styles from "../../lib/styles.scss";
|
||||
|
||||
@translate()
|
||||
@withForm
|
||||
|
@ -72,7 +73,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
data.enumOptions = '';
|
||||
data.dateFormat = 'eur';
|
||||
data.dateFormat = DateFormat.EUR;
|
||||
data.renderTemplate = '';
|
||||
|
||||
switch (data.type) {
|
||||
|
@ -374,8 +375,8 @@ export default class CUD extends Component {
|
|||
<Fieldset label={t('Field settings')}>
|
||||
<Dropdown id="dateFormat" label={t('Date format')}
|
||||
options={[
|
||||
{key: 'us', label: t('MM/DD/YYYY')},
|
||||
{key: 'eur', label: t('DD/MM/YYYY')}
|
||||
{key: DateFormat.US, label: t('MM/DD/YYYY')},
|
||||
{key: DateFormat.EU, label: t('DD/MM/YYYY')}
|
||||
]}
|
||||
/>
|
||||
<InputField id="default_value" label={t('Default value')} help={<Trans>Default value used when the field is empty.</Trans>}/>
|
||||
|
@ -387,8 +388,8 @@ export default class CUD extends Component {
|
|||
<Fieldset label={t('Field settings')}>
|
||||
<Dropdown id="dateFormat" label={t('Date format')}
|
||||
options={[
|
||||
{key: 'us', label: t('MM/DD')},
|
||||
{key: 'eur', label: t('DD/MM')}
|
||||
{key: DateFormat.US, label: t('MM/DD')},
|
||||
{key: DateFormat.EU, label: t('DD/MM')}
|
||||
]}
|
||||
/>
|
||||
<InputField id="default_value" label={t('Default value')} help={<Trans>Default value used when the field is empty.</Trans>}/>
|
||||
|
@ -445,7 +446,7 @@ export default class CUD extends Component {
|
|||
<InputField id="name" label={t('Name')}/>
|
||||
|
||||
{isEdit ?
|
||||
<StaticField id="type" className="mt-form-disabled" label={t('Type')}>{(this.fieldTypes[this.getFormValue('type')] || {}).label}</StaticField>
|
||||
<StaticField id="type" className={styles.formDisabled} label={t('Type')}>{(this.fieldTypes[this.getFormValue('type')] || {}).label}</StaticField>
|
||||
:
|
||||
<Dropdown id="type" label={t('Type')} options={typeOptions}/>
|
||||
}
|
||||
|
|
|
@ -40,9 +40,13 @@ const getStructure = t => {
|
|||
navs: {
|
||||
subscriptions: {
|
||||
title: t('Subscribers'),
|
||||
resolve: {
|
||||
segments: params => `/rest/segments/${params.listId}`
|
||||
},
|
||||
extraParams: [':segmentId?'],
|
||||
link: params => `/lists/${params.listId}/subscriptions`,
|
||||
visible: resolved => resolved.list.permissions.includes('viewSubscriptions'),
|
||||
render: props => <SubscriptionsList list={props.resolved.list} />
|
||||
render: props => <SubscriptionsList list={props.resolved.list} segments={props.resolved.segments} segmentId={props.match.params.segmentId} />
|
||||
},
|
||||
':action(edit|delete)': {
|
||||
title: t('Edit'),
|
||||
|
@ -163,7 +167,7 @@ const getStructure = t => {
|
|||
|
||||
export default function() {
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n }><Section root='/lists/1/segments/create' /* FIXME */ structure={getStructure}/></I18nextProvider>,
|
||||
<I18nextProvider i18n={ i18n }><Section root='/lists' structure={getStructure}/></I18nextProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
};
|
||||
|
|
|
@ -93,6 +93,10 @@ export default class CUD extends Component {
|
|||
await this.getFormValuesFromURL(`/rest/segments/${this.props.list.id}/${this.props.entity.id}`, data => {
|
||||
data.rootRuleType = data.settings.rootRule.type;
|
||||
data.selectedRule = null; // Validation errors of the selected rule are attached to this which makes sure we don't submit the segment if the opened rule has errors
|
||||
|
||||
this.setState({
|
||||
rulesTree: this.getTreeFromRules(data.settings.rootRule.rules)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ export default class CUD extends Component {
|
|||
this.state = {};
|
||||
|
||||
this.initForm({
|
||||
onChangeBeforeValidation: ::this.populateRuleDefaults,
|
||||
onChange: ::this.onFormChange
|
||||
});
|
||||
}
|
||||
|
@ -45,12 +46,12 @@ export default class CUD extends Component {
|
|||
const ruleHelpers = this.ruleHelpers;
|
||||
|
||||
let data;
|
||||
if (!ruleHelpers.isCompositeRuleType(rule.type)) {
|
||||
if (!ruleHelpers.isCompositeRuleType(rule.type)) { // rule.type === null signifies primitive rule where the type has not been determined yet
|
||||
data = ruleHelpers.primitiveRuleTypesFormDataDefaults;
|
||||
|
||||
const settings = ruleHelpers.getRuleTypeSettings(rule);
|
||||
if (settings) {
|
||||
data = settings.getFormData(rule);
|
||||
} else {
|
||||
data = {}; // This handles the case of a new rule, which does not have a type and column yet
|
||||
Object.assign(data, settings.getFormData(rule));
|
||||
}
|
||||
|
||||
data.type = rule.type || ''; // On '', we display label "--SELECT--" in the type dropdown. Null would not be accepted by React.
|
||||
|
@ -89,10 +90,10 @@ export default class CUD extends Component {
|
|||
|
||||
const ruleType = state.getIn(['type', 'value']);
|
||||
if (!ruleHelpers.isCompositeRuleType(ruleType)) {
|
||||
const columnType = state.getIn(['column', 'value']);
|
||||
const column = state.getIn(['column', 'value']);
|
||||
|
||||
if (columnType) {
|
||||
const colType = ruleHelpers.getColumnType(columnType);
|
||||
if (column) {
|
||||
const colType = ruleHelpers.getColumnType(column);
|
||||
|
||||
if (ruleType) {
|
||||
const settings = ruleHelpers.primitiveRuleTypes[colType][ruleType];
|
||||
|
@ -106,6 +107,27 @@ export default class CUD extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
populateRuleDefaults(mutState) {
|
||||
const ruleHelpers = this.ruleHelpers;
|
||||
const type = mutState.getIn(['data','type','value']);
|
||||
|
||||
if (!ruleHelpers.isCompositeRuleType(type)) {
|
||||
const column = mutState.getIn(['data', 'column', 'value']);
|
||||
|
||||
if (column) {
|
||||
const colType = ruleHelpers.getColumnType(column);
|
||||
|
||||
if (type) {
|
||||
const settings = ruleHelpers.primitiveRuleTypes[colType][type];
|
||||
if (!settings) {
|
||||
// The existing rule type does not fit the newly changed column. This resets the rule type chooser to "-- Select ---"
|
||||
mutState.setIn(['data', 'type', 'value'], '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFormChange(newState) {
|
||||
const noErrors = !newState.formState.get('data').find(attr => attr.get('error'));
|
||||
|
||||
|
@ -136,7 +158,6 @@ export default class CUD extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
const rule = this.props.rule;
|
||||
|
@ -153,7 +174,7 @@ export default class CUD extends Component {
|
|||
{ data: 3, title: t('Merge Tag') }
|
||||
];
|
||||
|
||||
const ruleColumnOptions = ruleHelpers.fields.map(fld => [ fld.column, fld.name, this.fieldTypes[fld.type].label, fld.tag || '' ]);
|
||||
const ruleColumnOptions = ruleHelpers.fields.map(fld => [ fld.column, fld.name, this.fieldTypes[fld.type].label, fld.key || '' ]);
|
||||
|
||||
const ruleColumnSelect = <TableSelect id="column" label={t('Field')} data={ruleColumnOptions} columns={ruleColumnOptionsColumns} dropdown withHeader selectionLabelIndex={1} />;
|
||||
let ruleTypeSelect = null;
|
||||
|
@ -186,6 +207,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.ruleOptions}>
|
||||
<h3>{t('Rule Options')}</h3>
|
||||
|
@ -198,6 +220,7 @@ export default class CUD extends Component {
|
|||
<Button type="submit" className="btn-primary" icon="chevron-left" label={t('OK')}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import {InputField} from "../../lib/form";
|
||||
import {DatePicker, Dropdown, InputField} from "../../lib/form";
|
||||
import { parseDate, parseBirthday, formatDate, formatBirthday, DateFormat, birthdayYear, getDateFormatString, getBirthdayFormatString } from '../../../../shared/date';
|
||||
|
||||
|
||||
export function getRuleHelpers(t, fields) {
|
||||
|
||||
function formatDate(date) {
|
||||
return date; // FIXME
|
||||
}
|
||||
|
||||
const ruleHelpers = {};
|
||||
|
||||
ruleHelpers.compositeRuleTypes = {
|
||||
|
@ -108,49 +106,72 @@ export function getRuleHelpers(t, fields) {
|
|||
}
|
||||
}
|
||||
|
||||
ruleHelpers.primitiveRuleTypes.date = ruleHelpers.primitiveRuleTypes.birthday = {
|
||||
ruleHelpers.primitiveRuleTypes.date = {
|
||||
eq: {
|
||||
dropdownLabel: t('On'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(rule.value)}),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
lt: {
|
||||
dropdownLabel: t('Before'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(rule.value)}),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
le: {
|
||||
dropdownLabel: t('Before or on'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(rule.value)}),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
gt: {
|
||||
dropdownLabel: t('After'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(rule.value)}),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
ge: {
|
||||
dropdownLabel: t('After or on'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(rule.value)}),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatDate(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
eqNowPlusDays: {
|
||||
dropdownLabel: t('On x-th day before/after now'),
|
||||
eqTodayPlusDays: {
|
||||
dropdownLabel: t('On x-th day before/after current date'),
|
||||
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is'),
|
||||
},
|
||||
ltNowPlusDays: {
|
||||
dropdownLabel: t('Before x-th day before/after now'),
|
||||
ltTodayPlusDays: {
|
||||
dropdownLabel: t('Before x-th day before/after current date'),
|
||||
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is before'),
|
||||
},
|
||||
leNowPlusDays: {
|
||||
dropdownLabel: t('Before or on x-th day before/after now'),
|
||||
leTodayPlusDays: {
|
||||
dropdownLabel: t('Before or on x-th day before/after current date'),
|
||||
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is before or on'),
|
||||
},
|
||||
gtNowPlusDays: {
|
||||
dropdownLabel: t('After x-th day before/after now'),
|
||||
gtTodayPlusDays: {
|
||||
dropdownLabel: t('After x-th day before/after current date'),
|
||||
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is after'),
|
||||
},
|
||||
geNowPlusDays: {
|
||||
dropdownLabel: t('After or on x-th day before/after now'),
|
||||
geTodayPlusDays: {
|
||||
dropdownLabel: t('After or on x-th day before/after current date'),
|
||||
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is after or on'),
|
||||
}
|
||||
};
|
||||
|
||||
ruleHelpers.primitiveRuleTypes.birthday = {
|
||||
eq: {
|
||||
dropdownLabel: t('On'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatBirthday(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
lt: {
|
||||
dropdownLabel: t('Before'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatBirthday(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
le: {
|
||||
dropdownLabel: t('Before or on'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is before or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatBirthday(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
gt: {
|
||||
dropdownLabel: t('After'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatBirthday(DateFormat.INTL, rule.value)}),
|
||||
},
|
||||
ge: {
|
||||
dropdownLabel: t('After or on'),
|
||||
treeLabel: rule => t('Date in column "{{colName}}" is after or on {{value}}', {colName: ruleHelpers.getColumnName(rule.column), value: formatBirthday(DateFormat.INTL, rule.value)}),
|
||||
}
|
||||
};
|
||||
|
||||
ruleHelpers.primitiveRuleTypes.option = {
|
||||
isTrue: {
|
||||
dropdownLabel: t('Is selected'),
|
||||
|
@ -194,7 +215,7 @@ export function getRuleHelpers(t, fields) {
|
|||
};
|
||||
|
||||
|
||||
const stringValueSettings = {
|
||||
const stringValueSettings = allowEmpty => ({
|
||||
form: <InputField id="value" label={t('Value')} />,
|
||||
getFormData: rule => ({
|
||||
value: rule.value
|
||||
|
@ -203,13 +224,13 @@ export function getRuleHelpers(t, fields) {
|
|||
rule.value = getter('value');
|
||||
},
|
||||
validate: state => {
|
||||
if (!state.getIn(['value', 'value'])) {
|
||||
if (!allowEmpty && !state.getIn(['value', 'value'])) {
|
||||
state.setIn(['value', 'error'], t('Value must not be empty'));
|
||||
} else {
|
||||
state.setIn(['value', 'error'], null);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const numberValueSettings = {
|
||||
form: <InputField id="value" label={t('Value')} />,
|
||||
|
@ -232,23 +253,79 @@ export function getRuleHelpers(t, fields) {
|
|||
};
|
||||
|
||||
const birthdayValueSettings = {
|
||||
form: <InputField id="value" label={t('Value')} /> // FIXME
|
||||
};
|
||||
|
||||
const birthdayRelativeValueSettings = {
|
||||
form: <InputField id="value" label={t('Value')} /> // FIXME
|
||||
form: <DatePicker id="value" label={t('Date')} birthday />,
|
||||
getFormData: rule => ({
|
||||
value: formatBirthday(DateFormat.INTL, rule.value)
|
||||
}),
|
||||
assignRuleSettings: (rule, getter) => {
|
||||
rule.value = parseBirthday(DateFormat.INTL, getter('value')).toISOString();
|
||||
},
|
||||
validate: state => {
|
||||
const value = state.getIn(['value', 'value']);
|
||||
const date = parseBirthday(DateFormat.INTL, value);
|
||||
if (!value) {
|
||||
state.setIn(['value', 'error'], t('Date must not be empty'));
|
||||
} else if (!date) {
|
||||
state.setIn(['value', 'error'], t('Date is invalid'));
|
||||
} else {
|
||||
state.setIn(['value', 'error'], null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const dateValueSettings = {
|
||||
form: <InputField id="value" label={t('Value')} /> // FIXME
|
||||
form: <DatePicker id="value" label={t('Date')} />,
|
||||
getFormData: rule => ({
|
||||
value: formatDate(DateFormat.INTL, rule.value)
|
||||
}),
|
||||
assignRuleSettings: (rule, getter) => {
|
||||
rule.value = parseDate(DateFormat.INTL, getter('value')).toISOString();
|
||||
},
|
||||
validate: state => {
|
||||
const value = state.getIn(['value', 'value']);
|
||||
const date = parseDate(DateFormat.INTL, value);
|
||||
if (!value) {
|
||||
state.setIn(['value', 'error'], t('Date must not be empty'));
|
||||
} else if (!date) {
|
||||
state.setIn(['value', 'error'], t('Date is invalid'));
|
||||
} else {
|
||||
state.setIn(['value', 'error'], null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const dateRelativeValueSettings = {
|
||||
form: <InputField id="value" label={t('Value')} /> // FIXME
|
||||
form:
|
||||
<div>
|
||||
<InputField id="value" label={t('Number of days')}/>
|
||||
<Dropdown id="direction" label={t('Before/After')} options={[
|
||||
{ key: 'before', label: t('Before current date') },
|
||||
{ key: 'after', label: t('After current date') }
|
||||
]}/>
|
||||
</div>,
|
||||
getFormData: rule => ({
|
||||
value: Math.abs(rule.value).toString(),
|
||||
direction: rule.value >= 0 ? 'after' : 'before'
|
||||
}),
|
||||
assignRuleSettings: (rule, getter) => {
|
||||
const direction = getter('direction');
|
||||
rule.value = parseInt(getter('value')) * (direction === 'before' ? -1 : 1);
|
||||
},
|
||||
validate: state => {
|
||||
const value = state.getIn(['value', 'value']);
|
||||
if (!value) {
|
||||
state.setIn(['value', 'error'], t('Value must not be empty'));
|
||||
} else if (isNaN(value)) {
|
||||
state.setIn(['value', 'error'], t('Value must be a number'));
|
||||
} else {
|
||||
state.setIn(['value', 'error'], null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const optionValueSettings = {
|
||||
form: null,
|
||||
formDataDefaults: {},
|
||||
getFormData: rule => ({}),
|
||||
assignRuleSettings: (rule, getter) => {},
|
||||
validate: state => {}
|
||||
|
@ -261,16 +338,24 @@ export function getRuleHelpers(t, fields) {
|
|||
}
|
||||
}
|
||||
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.text, Object.keys(ruleHelpers.primitiveRuleTypes.text), stringValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.website, Object.keys(ruleHelpers.primitiveRuleTypes.website), stringValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.number, Object.keys(ruleHelpers.primitiveRuleTypes.number), numberValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.text, ['eq', 'like', 're'], stringValueSettings(true));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.text, ['lt', 'le', 'gt', 'ge'], stringValueSettings(false));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.website, ['eq', 'like', 're'], stringValueSettings(true));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.number, ['eq', 'lt', 'le', 'gt', 'ge'], numberValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.birthday, ['eq', 'lt', 'le', 'gt', 'ge'], birthdayValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.birthday, ['eqNowPlusDays', 'ltNowPlusDays', 'leNowPlusDays', 'gtNowPlusDays', 'geNowPlusDays'], birthdayRelativeValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.date, ['eq', 'lt', 'le', 'gt', 'ge'], dateValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.date, ['eqNowPlusDays', 'ltNowPlusDays', 'leNowPlusDays', 'gtNowPlusDays', 'geNowPlusDays'], dateRelativeValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.option, Object.keys(ruleHelpers.primitiveRuleTypes.option), optionValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-enum'], Object.keys(ruleHelpers.primitiveRuleTypes['dropdown-enum']), stringValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], Object.keys(ruleHelpers.primitiveRuleTypes['radio-enum']), stringValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.date, ['eqTodayPlusDays', 'ltTodayPlusDays', 'leTodayPlusDays', 'gtTodayPlusDays', 'geTodayPlusDays'], dateRelativeValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes.option, ['isTrue', 'isFalse'], optionValueSettings);
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-enum'], ['eq', 'like', 're'], stringValueSettings(true));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['dropdown-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['eq', 'like', 're'], stringValueSettings(true));
|
||||
assignSettingsToRuleTypes(ruleHelpers.primitiveRuleTypes['radio-enum'], ['lt', 'le', 'gt', 'ge'], stringValueSettings(false));
|
||||
|
||||
ruleHelpers.primitiveRuleTypesFormDataDefaults = {
|
||||
value: '',
|
||||
direction: 'before'
|
||||
};
|
||||
|
||||
|
||||
|
||||
ruleHelpers.getCompositeRuleTypeOptions = () => {
|
||||
|
@ -283,24 +368,22 @@ export function getRuleHelpers(t, fields) {
|
|||
text: ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'],
|
||||
website: ['eq', 'like', 're'],
|
||||
number: ['eq', 'lt', 'le', 'gt', 'ge'],
|
||||
birthday: ['eq', 'lt', 'le', 'gt', 'ge', 'eqNowPlusDays', 'ltNowPlusDays', 'leNowPlusDays', 'gtNowPlusDays', 'geNowPlusDays'],
|
||||
date: ['eq', 'lt', 'le', 'gt', 'ge', 'eqNowPlusDays', 'ltNowPlusDays', 'leNowPlusDays', 'gtNowPlusDays', 'geNowPlusDays'],
|
||||
birthday: ['eq', 'lt', 'le', 'gt', 'ge'],
|
||||
date: ['eq', 'lt', 'le', 'gt', 'ge', 'eqTodayPlusDays', 'ltTodayPlusDays', 'leTodayPlusDays', 'gtTodayPlusDays', 'geTodayPlusDays'],
|
||||
option: ['isTrue', 'isFalse'],
|
||||
'radio-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'],
|
||||
'dropdown-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge']
|
||||
'dropdown-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge'],
|
||||
'radio-enum': ['eq', 'like', 're', 'lt', 'le', 'gt', 'ge']
|
||||
};
|
||||
|
||||
return order[columnType].map(key => ({ key, label: ruleHelpers.primitiveRuleTypes[columnType][key].dropdownLabel }));
|
||||
};
|
||||
|
||||
|
||||
|
||||
const predefColumns = [
|
||||
{
|
||||
column: 'email',
|
||||
name: t('Email address'),
|
||||
type: 'text',
|
||||
tag: 'EMAIL'
|
||||
key: 'EMAIL'
|
||||
},
|
||||
{
|
||||
column: 'opt_in_country',
|
||||
|
@ -329,7 +412,7 @@ export function getRuleHelpers(t, fields) {
|
|||
...fields.filter(fld => fld.type in ruleHelpers.primitiveRuleTypes)
|
||||
];
|
||||
|
||||
ruleHelpers.fieldsByColumn = [];
|
||||
ruleHelpers.fieldsByColumn = {};
|
||||
for (const fld of ruleHelpers.fields) {
|
||||
ruleHelpers.fieldsByColumn[fld.column] = fld;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
Dropdown, Form,
|
||||
withForm
|
||||
} from '../../lib/form';
|
||||
import axios from '../../lib/axios';
|
||||
|
||||
@translate()
|
||||
@withForm
|
||||
|
@ -24,62 +23,48 @@ export default class List extends Component {
|
|||
super(props);
|
||||
|
||||
const t = props.t;
|
||||
this.state = {
|
||||
segmentOptions: [
|
||||
{key: 'none', label: t('All subscriptions')}
|
||||
]
|
||||
};
|
||||
this.state = {};
|
||||
|
||||
this.subscriptionStatusLabels = {
|
||||
[SubscriptionStatus.SUBSCRIBED]: t('Subscribed'),
|
||||
[SubscriptionStatus.UNSUBSCRIBED]: t('Unubscribed'),
|
||||
[SubscriptionStatus.BOUNCED]: t('Bounced'),
|
||||
[SubscriptionStatus.COMPLAINED]: t('Complained'),
|
||||
}
|
||||
};
|
||||
|
||||
this.initForm({
|
||||
onChange: {
|
||||
segment: ::this.onSegmentChange
|
||||
segment: (newState, key, oldValue, value) => {
|
||||
this.navigateTo(`/lists/${this.props.list.id}/subscriptions` + (value ? '/' + value : ''));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
list: PropTypes.object
|
||||
list: PropTypes.object,
|
||||
segments: PropTypes.array,
|
||||
segmentId: PropTypes.string
|
||||
}
|
||||
|
||||
onSegmentChange(state, attr, oldValue, newValue) {
|
||||
// TODO
|
||||
|
||||
this.subscriptionsTable.refresh();
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async loadSegmentOptions() {
|
||||
const t = this.props.t;
|
||||
|
||||
const result = await axios.get(`/rest/segments/${this.props.list.id}`);
|
||||
|
||||
this.setState({
|
||||
segmentOptions: [
|
||||
{key: 'none', label: t('All subscriptions')},
|
||||
...result.data.map(x => ({ key: x.id.toString(), label: x.name})),
|
||||
]
|
||||
updateSegmentSelection(props) {
|
||||
this.populateFormValues({
|
||||
segment: props.segmentId || ''
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.populateFormValues({
|
||||
segment: 'none'
|
||||
});
|
||||
|
||||
this.loadSegmentOptions();
|
||||
this.updateSegmentSelection(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.updateSegmentSelection(nextProps);
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
const list = this.props.list;
|
||||
const segments = this.props.segments;
|
||||
|
||||
const columns = [
|
||||
{ data: 2, title: t('Email') },
|
||||
|
@ -96,6 +81,17 @@ export default class List extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
const segmentOptions = [
|
||||
{key: '', label: t('All subscriptions')},
|
||||
...segments.map(x => ({ key: x.id.toString(), label: x.name}))
|
||||
]
|
||||
|
||||
|
||||
let dataUrl = '/rest/subscriptions-table/' + list.id;
|
||||
if (this.props.segmentId) {
|
||||
dataUrl += '/' + this.props.segmentId;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
|
@ -110,12 +106,12 @@ export default class List extends Component {
|
|||
|
||||
<div className="well well-sm">
|
||||
<Form format="inline" stateOwner={this}>
|
||||
<Dropdown format="inline" className="input-sm" id="segment" label={t('Segment')} options={this.state.segmentOptions}/>
|
||||
<Dropdown format="inline" className="input-sm" id="segment" label={t('Segment')} options={segmentOptions}/>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
|
||||
<Table ref={node => this.subscriptionsTable = node} withHeader dataUrl={`/rest/subscriptions-table/${list.id}`} columns={columns} />
|
||||
<Table ref={node => this.subscriptionsTable = node} withHeader dataUrl={dataUrl} columns={columns} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue