Rendering of custom fields in subscription list
This commit is contained in:
parent
6f5b50e932
commit
c343e4efd3
6 changed files with 253 additions and 109 deletions
|
@ -12,6 +12,7 @@ import { withErrorHandling } from '../lib/error-handling';
|
||||||
import { DeleteModalDialog } from '../lib/modals';
|
import { DeleteModalDialog } from '../lib/modals';
|
||||||
import { validateNamespace, NamespaceSelect } from '../lib/namespace';
|
import { validateNamespace, NamespaceSelect } from '../lib/namespace';
|
||||||
import { UnsubscriptionMode } from '../../../shared/lists';
|
import { UnsubscriptionMode } from '../../../shared/lists';
|
||||||
|
import styles from "../lib/styles.scss";
|
||||||
|
|
||||||
@translate()
|
@translate()
|
||||||
@withForm
|
@withForm
|
||||||
|
@ -162,7 +163,7 @@ export default class CUD extends Component {
|
||||||
<InputField id="name" label={t('Name')}/>
|
<InputField id="name" label={t('Name')}/>
|
||||||
|
|
||||||
{isEdit &&
|
{isEdit &&
|
||||||
<StaticField id="cid" label="List ID" help={t('This is the list ID displayed to the subscribers')}>
|
<StaticField id="cid" className={styles.formDisabled} label="List ID" help={t('This is the list ID displayed to the subscribers')}>
|
||||||
{this.getFormValue('cid')}
|
{this.getFormValue('cid')}
|
||||||
</StaticField>
|
</StaticField>
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
} from '../../lib/form';
|
} from '../../lib/form';
|
||||||
import {Icon} from "../../lib/bootstrap-components";
|
import {Icon} from "../../lib/bootstrap-components";
|
||||||
import axios from '../../lib/axios';
|
import axios from '../../lib/axios';
|
||||||
import {getSubscriptionStatusLabels} from './helpers';
|
import {getFieldTypes, getSubscriptionStatusLabels} from './helpers';
|
||||||
|
|
||||||
@translate()
|
@translate()
|
||||||
@withForm
|
@withForm
|
||||||
|
@ -30,6 +30,7 @@ export default class List extends Component {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
|
|
||||||
this.subscriptionStatusLabels = getSubscriptionStatusLabels(t);
|
this.subscriptionStatusLabels = getSubscriptionStatusLabels(t);
|
||||||
|
this.fieldTypes = getFieldTypes(t);
|
||||||
|
|
||||||
this.initForm({
|
this.initForm({
|
||||||
onChange: {
|
onChange: {
|
||||||
|
@ -90,10 +91,16 @@ export default class List extends Component {
|
||||||
];
|
];
|
||||||
|
|
||||||
let colIdx = 5;
|
let colIdx = 5;
|
||||||
|
|
||||||
for (const fld of list.listFields) {
|
for (const fld of list.listFields) {
|
||||||
|
|
||||||
|
const indexable = this.fieldTypes[fld.type].indexable;
|
||||||
|
|
||||||
columns.push({
|
columns.push({
|
||||||
data: colIdx,
|
data: colIdx,
|
||||||
title: fld.name
|
title: fld.name,
|
||||||
|
sortable: indexable,
|
||||||
|
searchable: indexable
|
||||||
});
|
});
|
||||||
|
|
||||||
colIdx += 1;
|
colIdx += 1;
|
||||||
|
|
|
@ -20,156 +20,163 @@ export function getSubscriptionStatusLabels(t) {
|
||||||
|
|
||||||
export function getFieldTypes(t) {
|
export function getFieldTypes(t) {
|
||||||
|
|
||||||
const fieldTypes = {};
|
const groupedFieldTypes = {};
|
||||||
|
|
||||||
const stringFieldType = long => ({
|
const stringFieldType = long => ({
|
||||||
form: field => long ? <TextArea key={getFieldKey(field)} id={getFieldKey(field)} label={field.name}/> : <InputField key={getFieldKey(field)} id={getFieldKey(field)} label={field.name}/>,
|
form: groupedField => long ? <TextArea key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name}/> : <InputField key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name}/>,
|
||||||
assignFormData: (field, data) => {},
|
assignFormData: (groupedField, data) => {},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {},
|
assignEntity: (groupedField, data) => {},
|
||||||
validate: (field, state) => {}
|
validate: (groupedField, state) => {},
|
||||||
|
indexable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const numberFieldType = {
|
const numberFieldType = {
|
||||||
form: field => <InputField key={getFieldKey(field)} id={getFieldKey(field)} label={field.name}/>,
|
form: groupedField => <InputField key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name}/>,
|
||||||
assignFormData: (field, data) => {
|
assignFormData: (groupedField, data) => {
|
||||||
const value = data[getFieldKey(field)];
|
const value = data[getFieldKey(groupedField)];
|
||||||
data[getFieldKey(field)] = value ? value.toString() : '';
|
data[getFieldKey(groupedField)] = value ? value.toString() : '';
|
||||||
},
|
},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {
|
assignEntity: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = parseInt(data[getFieldKey(field)]);
|
data[getFieldKey(groupedField)] = parseInt(data[getFieldKey(groupedField)]);
|
||||||
},
|
},
|
||||||
validate: (field, state) => {
|
validate: (groupedField, state) => {
|
||||||
const value = state.getIn([getFieldKey(field), 'value']).trim();
|
const value = state.getIn([getFieldKey(groupedField), 'value']).trim();
|
||||||
if (value !== '' && isNaN(value)) {
|
if (value !== '' && isNaN(value)) {
|
||||||
state.setIn([getFieldKey(field), 'error'], t('Value must be a number'));
|
state.setIn([getFieldKey(groupedField), 'error'], t('Value must be a number'));
|
||||||
} else {
|
} else {
|
||||||
state.setIn([getFieldKey(field), 'error'], null);
|
state.setIn([getFieldKey(groupedField), 'error'], null);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
indexable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const dateFieldType = {
|
const dateFieldType = {
|
||||||
form: field => <DatePicker key={getFieldKey(field)} id={getFieldKey(field)} label={field.name} dateFormat={field.settings.dateFormat} />,
|
form: groupedField => <DatePicker key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name} dateFormat={groupedField.settings.dateFormat} />,
|
||||||
assignFormData: (field, data) => {
|
assignFormData: (groupedField, data) => {
|
||||||
const value = data[getFieldKey(field)];
|
const value = data[getFieldKey(groupedField)];
|
||||||
data[getFieldKey(field)] = value ? formatDate(field.settings.dateFormat, value) : '';
|
data[getFieldKey(groupedField)] = value ? formatDate(groupedField.settings.dateFormat, value) : '';
|
||||||
},
|
},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {
|
assignEntity: (groupedField, data) => {
|
||||||
const date = parseDate(field.settings.dateFormat, data[getFieldKey(field)]);
|
const date = parseDate(groupedField.settings.dateFormat, data[getFieldKey(groupedField)]);
|
||||||
data[getFieldKey(field)] = date;
|
data[getFieldKey(groupedField)] = date;
|
||||||
},
|
},
|
||||||
validate: (field, state) => {
|
validate: (groupedField, state) => {
|
||||||
const value = state.getIn([getFieldKey(field), 'value']);
|
const value = state.getIn([getFieldKey(groupedField), 'value']);
|
||||||
const date = parseDate(field.settings.dateFormat, value);
|
const date = parseDate(groupedField.settings.dateFormat, value);
|
||||||
if (value !== '' && !date) {
|
if (value !== '' && !date) {
|
||||||
state.setIn([getFieldKey(field), 'error'], t('Date is invalid'));
|
state.setIn([getFieldKey(groupedField), 'error'], t('Date is invalid'));
|
||||||
} else {
|
} else {
|
||||||
state.setIn([getFieldKey(field), 'error'], null);
|
state.setIn([getFieldKey(groupedField), 'error'], null);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
indexable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const birthdayFieldType = {
|
const birthdayFieldType = {
|
||||||
form: field => <DatePicker key={getFieldKey(field)} id={getFieldKey(field)} label={field.name} dateFormat={field.settings.dateFormat} birthday />,
|
form: groupedField => <DatePicker key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name} dateFormat={groupedField.settings.dateFormat} birthday />,
|
||||||
assignFormData: (field, data) => {
|
assignFormData: (groupedField, data) => {
|
||||||
const value = data[getFieldKey(field)];
|
const value = data[getFieldKey(groupedField)];
|
||||||
data[getFieldKey(field)] = value ? formatBirthday(field.settings.dateFormat, value) : '';
|
data[getFieldKey(groupedField)] = value ? formatBirthday(groupedField.settings.dateFormat, value) : '';
|
||||||
},
|
},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {
|
assignEntity: (groupedField, data) => {
|
||||||
const date = parseBirthday(field.settings.dateFormat, data[getFieldKey(field)]);
|
const date = parseBirthday(groupedField.settings.dateFormat, data[getFieldKey(groupedField)]);
|
||||||
data[getFieldKey(field)] = date;
|
data[getFieldKey(groupedField)] = date;
|
||||||
},
|
},
|
||||||
validate: (field, state) => {
|
validate: (groupedField, state) => {
|
||||||
const value = state.getIn([getFieldKey(field), 'value']);
|
const value = state.getIn([getFieldKey(groupedField), 'value']);
|
||||||
const date = parseBirthday(field.settings.dateFormat, value);
|
const date = parseBirthday(groupedField.settings.dateFormat, value);
|
||||||
if (value !== '' && !date) {
|
if (value !== '' && !date) {
|
||||||
state.setIn([getFieldKey(field), 'error'], t('Date is invalid'));
|
state.setIn([getFieldKey(groupedField), 'error'], t('Date is invalid'));
|
||||||
} else {
|
} else {
|
||||||
state.setIn([getFieldKey(field), 'error'], null);
|
state.setIn([getFieldKey(groupedField), 'error'], null);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
indexable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const jsonFieldType = {
|
const jsonFieldType = {
|
||||||
form: field => <ACEEditor key={getFieldKey(field)} id={getFieldKey(field)} label={field.name} mode="json" height="300px"/>,
|
form: groupedField => <ACEEditor key={getFieldKey(groupedField)} id={getFieldKey(groupedField)} label={groupedField.name} mode="json" height="300px"/>,
|
||||||
assignFormData: (field, data) => {},
|
assignFormData: (groupedField, data) => {},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {},
|
assignEntity: (groupedField, data) => {},
|
||||||
validate: (field, state) => {}
|
validate: (groupedField, state) => {},
|
||||||
|
indexable: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const enumSingleFieldType = componentType => ({
|
const enumSingleFieldType = componentType => ({
|
||||||
form: field => React.createElement(componentType, { key: getFieldKey(field), id: getFieldKey(field), label: field.name, options: field.settings.options }, null),
|
form: groupedField => React.createElement(componentType, { key: getFieldKey(groupedField), id: getFieldKey(groupedField), label: groupedField.name, options: groupedField.settings.options }, null),
|
||||||
assignFormData: (field, data) => {
|
assignFormData: (groupedField, data) => {
|
||||||
if (data[getFieldKey(field)] === null) {
|
if (data[getFieldKey(groupedField)] === null) {
|
||||||
if (field.default_value) {
|
if (groupedField.default_value) {
|
||||||
data[getFieldKey(field)] = field.default_value;
|
data[getFieldKey(groupedField)] = groupedField.default_value;
|
||||||
} else if (field.settings.options.length > 0) {
|
} else if (groupedField.settings.options.length > 0) {
|
||||||
data[getFieldKey(field)] = field.settings.options[0].key;
|
data[getFieldKey(groupedField)] = groupedField.settings.options[0].key;
|
||||||
} else {
|
} else {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
if (field.default_value) {
|
if (groupedField.default_value) {
|
||||||
data[getFieldKey(field)] = field.default_value;
|
data[getFieldKey(groupedField)] = groupedField.default_value;
|
||||||
} else if (field.settings.options.length > 0) {
|
} else if (groupedField.settings.options.length > 0) {
|
||||||
data[getFieldKey(field)] = field.settings.options[0].key;
|
data[getFieldKey(groupedField)] = groupedField.settings.options[0].key;
|
||||||
} else {
|
} else {
|
||||||
data[getFieldKey(field)] = '';
|
data[getFieldKey(groupedField)] = '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {
|
assignEntity: (groupedField, data) => {
|
||||||
},
|
},
|
||||||
validate: (field, state) => {}
|
validate: (groupedField, state) => {},
|
||||||
|
indexable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const enumMultipleFieldType = componentType => ({
|
const enumMultipleFieldType = componentType => ({
|
||||||
form: field => React.createElement(componentType, { key: getFieldKey(field), id: getFieldKey(field), label: field.name, options: field.settings.options }, null),
|
form: groupedField => React.createElement(componentType, { key: getFieldKey(groupedField), id: getFieldKey(groupedField), label: groupedField.name, options: groupedField.settings.options }, null),
|
||||||
assignFormData: (field, data) => {
|
assignFormData: (groupedField, data) => {
|
||||||
if (data[getFieldKey(field)] === null) {
|
if (data[getFieldKey(groupedField)] === null) {
|
||||||
data[getFieldKey(field)] = [];
|
data[getFieldKey(groupedField)] = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initFormData: (field, data) => {
|
initFormData: (groupedField, data) => {
|
||||||
data[getFieldKey(field)] = [];
|
data[getFieldKey(groupedField)] = [];
|
||||||
},
|
},
|
||||||
assignEntity: (field, data) => {},
|
assignEntity: (groupedField, data) => {},
|
||||||
validate: (field, state) => {}
|
validate: (groupedField, state) => {},
|
||||||
|
indexable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
fieldTypes.text = stringFieldType(false);
|
groupedFieldTypes.text = stringFieldType(false);
|
||||||
fieldTypes.website = stringFieldType(false);
|
groupedFieldTypes.website = stringFieldType(false);
|
||||||
fieldTypes.longtext = stringFieldType(true);
|
groupedFieldTypes.longtext = stringFieldType(true);
|
||||||
fieldTypes.gpg = stringFieldType(true);
|
groupedFieldTypes.gpg = stringFieldType(true);
|
||||||
fieldTypes.number = numberFieldType;
|
groupedFieldTypes.number = numberFieldType;
|
||||||
fieldTypes.date = dateFieldType;
|
groupedFieldTypes.date = dateFieldType;
|
||||||
fieldTypes.birthday = birthdayFieldType;
|
groupedFieldTypes.birthday = birthdayFieldType;
|
||||||
fieldTypes.json = jsonFieldType;
|
groupedFieldTypes.json = jsonFieldType;
|
||||||
fieldTypes['dropdown-enum'] = enumSingleFieldType(Dropdown);
|
groupedFieldTypes['dropdown-enum'] = enumSingleFieldType(Dropdown);
|
||||||
fieldTypes['radio-enum'] = enumSingleFieldType(RadioGroup);
|
groupedFieldTypes['radio-enum'] = enumSingleFieldType(RadioGroup);
|
||||||
|
|
||||||
// Here we rely on the fact the model/fields and model/subscriptions preprocess the field info and subscription
|
// Here we rely on the fact the model/groupedFields and model/subscriptions preprocess the groupedField info and subscription
|
||||||
// such that the grouped entries behave the same as the enum entries
|
// such that the grouped entries behave the same as the enum entries
|
||||||
fieldTypes['checkbox-grouped'] = enumMultipleFieldType(CheckBoxGroup);
|
groupedFieldTypes['checkbox-grouped'] = enumMultipleFieldType(CheckBoxGroup);
|
||||||
fieldTypes['radio-grouped'] = enumSingleFieldType(RadioGroup);
|
groupedFieldTypes['radio-grouped'] = enumSingleFieldType(RadioGroup);
|
||||||
fieldTypes['dropdown-grouped'] = enumSingleFieldType(Dropdown);
|
groupedFieldTypes['dropdown-grouped'] = enumSingleFieldType(Dropdown);
|
||||||
|
|
||||||
return fieldTypes;
|
return groupedFieldTypes;
|
||||||
}
|
}
|
|
@ -67,7 +67,7 @@ async function ajaxListTx(tx, params, queryFun, columns, options) {
|
||||||
query.limit(limit);
|
query.limit(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
query.select(columnsSelect);
|
query.select([...columnsSelect, ...options.extraColumns || [] ]);
|
||||||
|
|
||||||
for (const order of params.order) {
|
for (const order of params.order) {
|
||||||
if (options.orderByBuilder) {
|
if (options.orderByBuilder) {
|
||||||
|
@ -157,7 +157,8 @@ async function ajaxListWithPermissionsTx(tx, context, fetchSpecs, params, queryF
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
orderByBuilder: options.orderByBuilder
|
orderByBuilder: options.orderByBuilder,
|
||||||
|
extraColumns: options.extraColumns
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,7 @@ async function getById(context, listId, id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listTx(tx, listId) {
|
async function listTx(tx, listId) {
|
||||||
return await tx('custom_fields').where({list: listId}).select(['id', 'name', 'type', 'key', 'column', 'order_list', 'settings', 'group', 'order_subscribe', 'order_manage']).orderBy(knex.raw('-order_list'), 'desc').orderBy('id', 'asc');
|
return await tx('custom_fields').where({list: listId}).select(['id', 'name', 'type', 'key', 'column', 'settings', 'group', 'default_value', 'order_list', 'order_subscribe', 'order_manage']).orderBy(knex.raw('-order_list'), 'desc').orderBy('id', 'asc');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function list(context, listId) {
|
async function list(context, listId) {
|
||||||
|
@ -160,7 +160,7 @@ async function list(context, listId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listGroupedTx(tx, listId) {
|
async function listGroupedTx(tx, listId) {
|
||||||
const flds = await tx('custom_fields').where({list: listId}).select(['id', 'name', 'type', 'column', 'settings', 'group', 'default_value']).orderBy(knex.raw('-order_list'), 'desc').orderBy('id', 'asc');
|
const flds = await listTx(tx, listId);
|
||||||
|
|
||||||
const fldsById = {};
|
const fldsById = {};
|
||||||
for (const fld of flds) {
|
for (const fld of flds) {
|
||||||
|
@ -199,7 +199,7 @@ async function listGrouped(context, listId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listByOrderListTx(tx, listId, extraColumns = []) {
|
async function listByOrderListTx(tx, listId, extraColumns = []) {
|
||||||
return await tx('custom_fields').where({list: listId}).whereNotNull('order_list').select(['name', ...extraColumns]).orderBy('order_list', 'asc');
|
return await tx('custom_fields').where({list: listId}).whereNotNull('order_list').select(['name', 'type', ...extraColumns]).orderBy('order_list', 'asc');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listDTAjax(context, listId, params) {
|
async function listDTAjax(context, listId, params) {
|
||||||
|
|
|
@ -11,9 +11,68 @@ const { SubscriptionStatus, getFieldKey } = require('../shared/lists');
|
||||||
const segments = require('./segments');
|
const segments = require('./segments');
|
||||||
const { enforce, filterObject } = require('../lib/helpers');
|
const { enforce, filterObject } = require('../lib/helpers');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const { formatDate, formatBirthday } = require('../shared/date');
|
||||||
|
|
||||||
const allowedKeysBase = new Set(['email', 'tz', 'is_test', 'status']);
|
const allowedKeysBase = new Set(['email', 'tz', 'is_test', 'status']);
|
||||||
|
|
||||||
|
const fieldTypes = {};
|
||||||
|
|
||||||
|
const Cardinality = {
|
||||||
|
SINGLE: 0,
|
||||||
|
MULTIPLE: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
function getOptionsMap(groupedField) {
|
||||||
|
const result = {};
|
||||||
|
for (const opt of groupedField.settings.options) {
|
||||||
|
result[opt.key] = opt.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldTypes.text = fieldTypes.website = fieldTypes.longtext = fieldTypes.gpg = fieldTypes.number = {
|
||||||
|
afterJSON: (groupedField, entity) => {},
|
||||||
|
listRender: (groupedField, value) => value
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldTypes.json = {
|
||||||
|
afterJSON: (groupedField, entity) => {},
|
||||||
|
listRender: (groupedField, value) => value
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldTypes['checkbox-grouped'] = {
|
||||||
|
afterJSON: (groupedField, entity) => {},
|
||||||
|
listRender: (groupedField, value) => {
|
||||||
|
const optMap = getOptionsMap(groupedField);
|
||||||
|
return value.map(x => optMap[x]).join(', ');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldTypes['radio-enum'] = fieldTypes['dropdown-enum'] = fieldTypes['radio-grouped'] = fieldTypes['dropdown-grouped'] = {
|
||||||
|
afterJSON: (groupedField, entity) => {},
|
||||||
|
listRender: (groupedField, value) => {
|
||||||
|
const optMap = getOptionsMap(groupedField);
|
||||||
|
return optMap[value];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldTypes.date = {
|
||||||
|
afterJSON: (groupedField, entity) => {
|
||||||
|
entity[getFieldKey(groupedField)] = moment(entity[getFieldKey(groupedField)]).toDate();
|
||||||
|
},
|
||||||
|
listRender: (groupedField, value) => formatDate(groupedField.settings.dateFormat, value)
|
||||||
|
};
|
||||||
|
|
||||||
|
fieldTypes.birthday = {
|
||||||
|
afterJSON: (groupedField, entity) => {
|
||||||
|
entity[getFieldKey(groupedField)] = moment(entity[getFieldKey(groupedField)]).toDate();
|
||||||
|
},
|
||||||
|
listRender: (groupedField, value) => formatBirthday(groupedField.settings.dateFormat, value)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getTableName(listId) {
|
function getTableName(listId) {
|
||||||
return `subscription__${listId}`;
|
return `subscription__${listId}`;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +208,57 @@ async function listDTAjax(context, listId, segmentId, params) {
|
||||||
return await knex.transaction(async tx => {
|
return await knex.transaction(async tx => {
|
||||||
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'viewSubscriptions');
|
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'viewSubscriptions');
|
||||||
|
|
||||||
const flds = await fields.listByOrderListTx(tx, listId, ['column']);
|
// All the data transformation below is to reuse ajaxListTx and groupSubscription methods so as to keep the code DRY
|
||||||
|
// We first construct the columns to contain all which is supposed to be show and extraColumns which contain
|
||||||
|
// everything else that constitutes the subscription.
|
||||||
|
// Then in ajaxList's mapFunc, we construct the entity from the fields ajaxList retrieved and pass it to groupSubscription
|
||||||
|
// to group the fields. Then we copy relevant values form grouped subscription to ajaxList's data which then get
|
||||||
|
// returned to the client. During the copy, we also render the values.
|
||||||
|
|
||||||
|
const groupedFieldsMap = await getGroupedFieldsMap(tx, listId);
|
||||||
|
const listFlds = await fields.listByOrderListTx(tx, listId, ['column', 'id']);
|
||||||
|
|
||||||
|
const columns = ['id', 'cid', 'email', 'status', 'created'];
|
||||||
|
const extraColumns = [];
|
||||||
|
let listFldIdx = columns.length;
|
||||||
|
const idxMap = {};
|
||||||
|
|
||||||
|
for (const listFld of listFlds) {
|
||||||
|
const fldKey = getFieldKey(listFld);
|
||||||
|
const fld = groupedFieldsMap[fldKey];
|
||||||
|
|
||||||
|
if (fld.column) {
|
||||||
|
columns.push(fld.column);
|
||||||
|
} else {
|
||||||
|
columns.push({
|
||||||
|
name: fldKey,
|
||||||
|
raw: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
idxMap[fldKey] = listFldIdx;
|
||||||
|
listFldIdx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const fldKey in groupedFieldsMap) {
|
||||||
|
const fld = groupedFieldsMap[fldKey];
|
||||||
|
|
||||||
|
if (fld.column) {
|
||||||
|
if (!(fldKey in idxMap)) {
|
||||||
|
extraColumns.push(fld.column);
|
||||||
|
idxMap[fldKey] = listFldIdx;
|
||||||
|
listFldIdx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (const optionColumn in fld.groupedOptions) {
|
||||||
|
extraColumns.push(optionColumn);
|
||||||
|
idxMap[optionColumn] = listFldIdx;
|
||||||
|
listFldIdx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const addSegmentQuery = segmentId ? await segments.getQueryGeneratorTx(tx, listId, segmentId) : () => {};
|
const addSegmentQuery = segmentId ? await segments.getQueryGeneratorTx(tx, listId, segmentId) : () => {};
|
||||||
|
|
||||||
return await dtHelpers.ajaxListTx(
|
return await dtHelpers.ajaxListTx(
|
||||||
|
@ -162,8 +271,28 @@ async function listDTAjax(context, listId, segmentId, params) {
|
||||||
});
|
});
|
||||||
return query;
|
return query;
|
||||||
},
|
},
|
||||||
['id', 'cid', 'email', 'status', 'created', ...flds.map(fld => fld.column)]
|
columns,
|
||||||
// FIXME - adapt data in custom columns to render them properly
|
{
|
||||||
|
mapFun: data => {
|
||||||
|
const entity = {};
|
||||||
|
for (const fldKey in idxMap) {
|
||||||
|
// This is a bit of hacking. We rely on the fact that if a field has a column, then the column is the field key.
|
||||||
|
// Then it has the group id with value 0. groupSubscription will be able to process the fields that have a column
|
||||||
|
// and it will assign values to the fields that don't have a value (i.e. those that currently have the group id and value 0).
|
||||||
|
entity[fldKey] = data[idxMap[fldKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
groupSubscription(groupedFieldsMap, entity);
|
||||||
|
|
||||||
|
for (const listFld of listFlds) {
|
||||||
|
const fldKey = getFieldKey(listFld);
|
||||||
|
const fld = groupedFieldsMap[fldKey];
|
||||||
|
data[idxMap[fldKey]] = fieldTypes[fld.type].listRender(fld, entity[fldKey]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
extraColumns
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -223,9 +352,8 @@ async function _validateAndPreprocess(tx, listId, groupedFieldsMap, entity, isCr
|
||||||
|
|
||||||
for (const key in groupedFieldsMap) {
|
for (const key in groupedFieldsMap) {
|
||||||
const fld = groupedFieldsMap[key];
|
const fld = groupedFieldsMap[key];
|
||||||
if (fld.type === 'date' || fld.type === 'birthday') {
|
|
||||||
entity[getFieldKey(fld)] = moment(entity[getFieldKey(fld)]).toDate();
|
fieldTypes[fld.type].afterJSON(fld, entity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue