import React from "react" import { Row, Col, Modal, Form, Input, Select, Button, Table, Icon, Tooltip, Tag, Popconfirm, Spin, notification } from "antd" import Utils from "./utils" import * as cs from "./constants" const tagColors = { "enabled": "green", "blacklisted": "red" } class CreateFormDef extends React.PureComponent { state = { confirmDirty: false, attribs: {}, modalWaiting: false } componentDidMount() { this.setState({ attribs: this.props.record.attribs }) } // Handle create / edit form submission. handleSubmit = (e) => { e.preventDefault() var err = null, values = {} this.props.form.validateFields((e, v) => { err = e values = v }) if(err) { return } values["attribs"] = {} let a = this.props.form.getFieldValue("attribs-json") if(a && a.length > 0) { try { values["attribs"] = JSON.parse(a) if(values["attribs"] instanceof Array) { notification["error"]({ message: "Invalid JSON type", description: "Attributes should be a map {} and not an array []" }) return } } catch(e) { notification["error"]({ message: "Invalid JSON in attributes", description: e.toString() }) return } } this.setState({ modalWaiting: true }) if (this.props.formType === cs.FormCreate) { // Add a subscriber. this.props.modelRequest(cs.ModelSubscribers, cs.Routes.CreateSubscriber, cs.MethodPost, values).then(() => { notification["success"]({ message: "Subscriber added", description: `${values["email"]} added` }) this.props.fetchRecords() this.props.onClose() this.setState({ modalWaiting: false }) }).catch(e => { notification["error"]({ message: "Error", description: e.message }) this.setState({ modalWaiting: false }) }) } else { // Edit a subscriber. delete(values["keys"]) delete(values["vals"]) this.props.modelRequest(cs.ModelSubscribers, cs.Routes.UpdateSubscriber, cs.MethodPut, { ...values, id: this.props.record.id }).then(() => { notification["success"]({ message: "Subscriber modified", description: `${values["email"]} modified` }) // Reload the table. this.props.fetchRecords() this.props.onClose() this.setState({ modalWaiting: false }) }).catch(e => { notification["error"]({ message: "Error", description: e.message }) this.setState({ modalWaiting: false }) }) } } modalTitle(formType, record) { if(formType === cs.FormCreate) { return "Add subscriber" } return ( { record.status } {" "} { record.name } ({ record.email }) ) } render() { const { formType, record, onClose } = this.props; const { getFieldDecorator } = this.props.form const formItemLayout = { labelCol: { xs: { span: 16 }, sm: { span: 4 } }, wrapperCol: { xs: { span: 16 }, sm: { span: 18 } } } if (formType === null) { return null } let subListIDs = [] let subStatuses = {} if(this.props.record && this.props.record.lists) { subListIDs = this.props.record.lists.map((v) => { return v["id"] }) subStatuses = this.props.record.lists.reduce((o, item) => ({ ...o, [item.id]: item.subscription_status}), {}) } else if(this.props.list) { subListIDs = [ this.props.list.id ] } return (
{getFieldDecorator("email", { initialValue: record.email, rules: [{ required: true }] })()} {getFieldDecorator("name", { initialValue: record.name, rules: [{ required: true }] })()} {getFieldDecorator("status", { initialValue: record.status ? record.status : "enabled", rules: [{ required: true, message: "Type is required" }] })( )} {getFieldDecorator("lists", { initialValue: subListIDs })( )}

Attributes

Attributes can be defined as a JSON map, for example: {'{"age": 30, "color": "red", "is_user": true}'}. More info.

{getFieldDecorator("attribs-json", { initialValue: JSON.stringify(this.state.attribs, null, 4) })( )}
) } } const CreateForm = Form.create()(CreateFormDef) class Subscribers extends React.PureComponent { defaultPerPage = 20 state = { formType: null, record: {}, queryParams: { page: 1, total: 0, perPage: this.defaultPerPage, listID: this.props.route.match.params.listID ? parseInt(this.props.route.match.params.listID, 10) : 0, list: null, query: null, targetLists: [] }, listAddVisible: false } // Pagination config. paginationOptions = { hideOnSinglePage: true, showSizeChanger: true, showQuickJumper: true, defaultPageSize: this.defaultPerPage, pageSizeOptions: ["20", "50", "70", "100"], position: "both", showTotal: (total, range) => `${range[0]} to ${range[1]} of ${total}`, onChange: (page, perPage) => { this.fetchRecords({ page: page, per_page: perPage }) }, onShowSizeChange: (page, perPage) => { this.fetchRecords({ page: page, per_page: perPage }) } } constructor(props) { super(props) // Table layout. this.columns = [{ title: "E-mail", dataIndex: "email", sorter: true, width: "25%", render: (text, record) => { return ( this.handleShowEditForm(record)}>{text} ) } }, { title: "Name", dataIndex: "name", sorter: true, width: "25%", render: (text, record) => { return ( this.handleShowEditForm(record)}>{text} ) } }, { title: "Status", dataIndex: "status", width: "5%", render: (status, _) => { return { status } } }, { title: "Lists", dataIndex: "lists", width: "10%", align: "center", render: (lists, _) => { return { lists.reduce((def, item) => def + (item.subscription_status !== cs.SubscriptionStatusUnsubscribed ? 1 : 0), 0) } } }, { title: "Created", width: "10%", dataIndex: "created_at", render: (date, _) => { return Utils.DateString(date) } }, { title: "Updated", width: "10%", dataIndex: "updated_at", render: (date, _) => { return Utils.DateString(date) } }, { title: "", dataIndex: "actions", width: "10%", render: (text, record) => { return (
{/* */} this.handleShowEditForm(record)}> this.handleDeleteRecord(record)}>
) } } ] } componentDidMount() { // Load lists on boot. this.props.modelRequest(cs.ModelLists, cs.Routes.GetLists, cs.MethodGet).then(() => { // If this is an individual list's view, pick up that list. if(this.state.queryParams.listID) { this.props.data[cs.ModelLists].forEach((l) => { if(l.id === this.state.queryParams.listID) { this.setState({ queryParams: { ...this.state.queryParams, list: l }}) return false } }) } }) this.fetchRecords() } fetchRecords = (params) => { let qParams = { page: this.state.queryParams.page, per_page: this.state.queryParams.per_page, list_id: this.state.queryParams.listID, query: this.state.queryParams.query } // The records are for a specific list. if(this.state.queryParams.listID) { qParams.list_id = this.state.queryParams.listID } if(params) { qParams = { ...qParams, ...params } } this.props.modelRequest(cs.ModelSubscribers, cs.Routes.GetSubscribers, cs.MethodGet, qParams).then(() => { this.setState({ queryParams: { ...this.state.queryParams, total: this.props.data[cs.ModelSubscribers].total, perPage: this.props.data[cs.ModelSubscribers].per_page, page: this.props.data[cs.ModelSubscribers].page, query: this.props.data[cs.ModelSubscribers].query, }}) }) } handleDeleteRecord = (record) => { this.props.modelRequest(cs.ModelSubscribers, cs.Routes.DeleteSubscriber, cs.MethodDelete, { id: record.id }) .then(() => { notification["success"]({ message: "Subscriber deleted", description: `${record.email} deleted` }) // Reload the table. this.fetchRecords() }).catch(e => { notification["error"]({ message: "Error", description: e.message }) }) } handleQuerySubscribersIntoLists = (query, sourceList, targetLists) => { let params = { query: query, source_list: sourceList, target_lists: targetLists } this.props.request(cs.Routes.QuerySubscribersIntoLists, cs.MethodPost, params).then((res) => { notification["success"]({ message: "Subscriber(s) added", description: `${ res.data.data.count } added` }) this.handleToggleListAdd() }).catch(e => { notification["error"]({ message: "Error", description: e.message }) }) } handleHideForm = () => { this.setState({ formType: null }) } handleShowCreateForm = () => { this.setState({ formType: cs.FormCreate, attribs: [], record: {} }) } handleShowEditForm = (record) => { this.setState({ formType: cs.FormEdit, record: record }) } handleToggleQueryForm = () => { // The query form is being cancelled. Reset the results. if(this.state.queryFormVisible) { this.fetchRecords({ query: null }) } this.setState({ queryFormVisible: !this.state.queryFormVisible }) } handleToggleListAdd = () => { this.setState({ listAddVisible: !this.state.listAddVisible }) } render() { const pagination = { ...this.paginationOptions, ...this.state.queryParams } return (

Subscribers { this.state.queryParams.list && » { this.state.queryParams.list.name } }

{ !this.state.queryFormVisible && Advanced }
{ this.state.queryFormVisible &&

Write a partial SQL expression to query the subscribers based on their primary information or attributes. Learn more.

{ this.setState({ queryParams: { ...this.state.queryParams, query: e.target.value } }) }} autosize={{ minRows: 2, maxRows: 10 }} />
{" "} {" "}
} `${record.id}-${record.email}` } dataSource={ this.props.data[cs.ModelSubscribers].results } loading={ this.props.reqStates[cs.ModelSubscribers] !== cs.StateDone } pagination={ pagination } rowSelection = {{ fixed: true }} /> { this.state.formType !== null && } { if(this.state.queryParams.targetLists.length == 0) { notification["warning"]({ message: "No lists selected", description: "Select one or more lists" }) return false } this.handleQuerySubscribersIntoLists( this.state.queryParams.query, this.state.queryParams.listID, this.state.queryParams.targetLists ) }} okButtonProps={{ disabled: this.props.reqStates[cs.ModelSubscribers] === cs.StatePending }}> ) } } export default Subscribers