import React from "react" import { Row, Col, Form, Select, Input, Upload, Button, Radio, Icon, Spin, Progress, Popconfirm, Tag, notification } from "antd" import * as cs from "./constants" const StatusNone = "none" const StatusImporting = "importing" const StatusStopping = "stopping" const StatusFinished = "finished" const StatusFailed = "failed" class TheFormDef extends React.PureComponent { state = { confirmDirty: false, fileList: [], formLoading: false, mode: "subscribe" } componentDidMount() { // Fetch lists. this.props.modelRequest(cs.ModelLists, cs.Routes.GetLists, cs.MethodGet, { per_page: "all" }) } // 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 } if (this.state.fileList.length < 1) { notification["error"]({ placement: cs.MsgPosition, message: "Error", description: "Select a valid file to upload" }) return } this.setState({ formLoading: true }) let params = new FormData() params.set("params", JSON.stringify(values)) params.append("file", this.state.fileList[0]) this.props .request(cs.Routes.UploadRouteImport, cs.MethodPost, params) .then(() => { notification["info"]({ placement: cs.MsgPosition, message: "File uploaded", description: "Please wait while the import is running" }) this.props.fetchimportState() this.setState({ formLoading: false }) }) .catch(e => { notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) this.props.fetchimportState() this.setState({ formLoading: false }) }) } handleConfirmBlur = e => { const value = e.target.value this.setState({ confirmDirty: this.state.confirmDirty || !!value }) } onFileChange = f => { let fileList = [f] this.setState({ fileList }) return false } render() { const { getFieldDecorator } = this.props.form const formItemLayout = { labelCol: { xs: { span: 16 }, sm: { span: 4 } }, wrapperCol: { xs: { span: 16 }, sm: { span: 10 } } } const formItemTailLayout = { wrapperCol: { xs: { span: 24, offset: 0 }, sm: { span: 10, offset: 4 } } } return (
{getFieldDecorator("mode", { rules: [{ required: true }], initialValue: "subscribe" })( { this.setState({ mode: e.target.value }) }} > Subscribe Blacklist )} {this.state.mode === "subscribe" && ( {getFieldDecorator("lists", { rules: [{ required: true }] })( )} )} {this.state.mode === "blacklist" && (

All existing subscribers found in the import will be marked as 'blacklisted' and will be unsubscribed from their existing subscriptions. New subscribers will be imported and marked as 'blacklisted'.

)} {getFieldDecorator("delim", { initialValue: "," })()}
{getFieldDecorator("file", { valuePropName: "file", getValueFromEvent: this.normFile, rules: [{ required: true }] })(

Click or drag a CSV or ZIP file here

)}

For existing subscribers, the names and attributes will be overwritten with the values in the CSV.

) } } const TheForm = Form.create()(TheFormDef) class Importing extends React.PureComponent { state = { pollID: -1, logs: "" } stopImport = () => { // Get the import status. this.props .request(cs.Routes.UploadRouteImport, cs.MethodDelete) .then(r => { this.props.fetchimportState() }) .catch(e => { notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) }) } componentDidMount() { // Poll for stats until it's finished or failed. let pollID = window.setInterval(() => { this.props.fetchimportState() this.fetchLogs() if ( this.props.importState.status === StatusFinished || this.props.importState.status === StatusFailed ) { window.clearInterval(this.state.pollID) } }, 1000) this.setState({ pollID: pollID }) } componentWillUnmount() { window.clearInterval(this.state.pollID) } fetchLogs() { this.props .request(cs.Routes.GetRouteImportLogs, cs.MethodGet) .then(r => { this.setState({ logs: r.data.data }) let t = document.querySelector("#log-textarea") t.scrollTop = t.scrollHeight }) .catch(e => { notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) }) } render() { let progressPercent = 0 if (this.props.importState.status === StatusFinished) { progressPercent = 100 } else { progressPercent = Math.floor( (this.props.importState.imported / this.props.importState.total) * 100 ) } return (

Importing — {this.props.importState.name}

{this.props.importState.status === StatusImporting && (

Import is in progress. It is safe to navigate away from this page.

)} {this.props.importState.status !== StatusImporting && (

Import has finished.

)}

{this.props.importState.imported} records


{this.props.importState.status === StatusImporting && ( this.stopImport()} >

)} {this.props.importState.status === StatusStopping && (

Stopping

)} {this.props.importState.status !== StatusImporting && this.props.importState.status !== StatusStopping && (
{this.props.importState.status !== StatusFinished && (
{this.props.importState.status}
)}
)}

Import log

) } } class Import extends React.PureComponent { state = { importState: { status: "" } } fetchimportState = () => { // Get the import status. this.props .request(cs.Routes.GetRouteImportStats, cs.MethodGet) .then(r => { this.setState({ importState: r.data.data }) }) .catch(e => { notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) }) } componentDidMount() { this.props.pageTitle("Import subscribers") this.fetchimportState() } render() { if (this.state.importState.status === "") { // Fetching the status. return (
) } else if (this.state.importState.status !== StatusNone) { // There's an import state return ( ) } return (

Import subscribers


Instructions

Upload a CSV file or a ZIP file with a single CSV file in it to bulk import subscribers. The CSV file should have the following headers with the exact column names. attributes (optional) should be a valid JSON string with double escaped quotes.

email, name, status, attributes

Example raw CSV

email, name, status, attributes user1@mail.com, "User One", enabled, {'"{""age"": 32, ""city"": ""Bangalore""}"'} user2@mail.com, "User Two", blacklisted, {'"{""age"": 25, ""occupation"": ""Time Traveller""}"'}
) } } export default Import