chaskiq/chaskiq

View on GitHub
app/javascript/src/pages/Campaigns.tsx

Summary

Maintainability
F
6 days
Test Coverage
import React, { Component } from 'react';
import { Route, Switch, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
// import Tabs from '@atlaskit/tabs';
import Moment from 'react-moment';
import CampaignSettings from './campaigns/settings';
import CampaignEditor from './campaigns/editor';

import { isEmpty } from 'lodash';

import graphql from '@chaskiq/store/src/graphql/client';

import { AnchorLink } from '@chaskiq/components/src/components/RouterLink';
import SwitchControl from '@chaskiq/components/src/components/Switch';
import Table from '@chaskiq/components/src/components/Table';
import Tabs from '@chaskiq/components/src/components/Tabs';
import Button from '@chaskiq/components/src/components/Button';
import CircularProgress from '@chaskiq/components/src/components/Progress';
import UpgradeButton from '@chaskiq/components/src/components/upgradeButton';
import SegmentManager from '@chaskiq/components/src/components/segmentManager';
import DeleteDialog from '@chaskiq/components/src/components/DeleteDialog';
import CampaignStats from '@chaskiq/components/src/components/stats';
import TourManager from '@chaskiq/components/src/components/Tour';
import ContentHeader from '@chaskiq/components/src/components/PageHeader';
import Content from '@chaskiq/components/src/components/Content';
import EmptyView from '@chaskiq/components/src/components/EmptyView';
import FilterMenu from '@chaskiq/components/src/components/FilterMenu';
import Badge from '@chaskiq/components/src/components/Badge';
import userFormat from '@chaskiq/components/src/components/Table/userFormat';

import { parseJwt, generateJWT } from '@chaskiq/store/src/jwt';

import { getAppUser } from '@chaskiq/store/src/actions/app_user';

import { toggleDrawer } from '@chaskiq/store/src/actions/drawer';

import {
  errorMessage,
  successMessage,
} from '@chaskiq/store/src/actions/status_messages';

import {
  setCurrentSection,
  setCurrentPage,
} from '@chaskiq/store/src/actions/navigation';

import {
  Pause,
  SendIcon,
  EmailIcon,
  MessageIcon,
  FilterFramesIcon,
  ClearAll,
  DeleteOutlineRounded,
  CopyContentIcon,
} from '@chaskiq/components/src/components/icons';

import I18n from '../shared/FakeI18n';

import {
  CAMPAIGN,
  CAMPAIGNS,
  CAMPAIGN_METRICS,
} from '@chaskiq/store/src/graphql/queries';
import {
  PREDICATES_SEARCH,
  UPDATE_CAMPAIGN,
  CREATE_CAMPAIGN,
  DELIVER_CAMPAIGN,
  PURGE_METRICS,
  DELETE_CAMPAIGN,
  CLONE_MESSAGE,
} from '@chaskiq/store/src/graphql/mutations';

type CampaignSegmentProps = {
  app: any;
  data: any;
  successMessage: () => void;
  updateData: (newData: any, cb?: any) => void;
  dispatch: (val: any) => void;
};

type CampaignSegmentState = {
  jwt: any;
  app_users: any;
  search: boolean;
  meta: any;
  searching: boolean;
};
class CampaignSegment extends Component<
  CampaignSegmentProps,
  CampaignSegmentState
> {
  constructor(props) {
    super(props);
    this.state = {
      jwt: null,
      app_users: [],
      search: false,
      meta: {},
      searching: false,
    };
  }

  componentDidMount() {
    /* this.props.actions.fetchAppSegment(
      this.props.app.segments[0].id
    ) */
    this.search();
  }

  handleSave = (_e) => {
    const predicates = parseJwt(this.state.jwt);
    // console.log(predicates)

    const params = {
      appKey: this.props.app.key,
      id: this.props.data.id,
      campaignParams: {
        segments: predicates.data,
      },
    };

    graphql(UPDATE_CAMPAIGN, params, {
      success: (_data) => {
        this.props.successMessage();
        this.setState({ jwt: null });
      },
      error: () => {},
    });
  };

  updateData = (data, cb = null) => {
    const newData = Object.assign({}, this.props.data, {
      segments: data.data,
    });
    this.props.updateData(newData, cb ? cb() : null);
  };

  updatePredicate = (data, cb = null) => {
    const jwtToken = generateJWT(data);
    // console.log(parseJwt(jwtToken))
    if (cb) cb(jwtToken);
    this.setState({ jwt: jwtToken }, () => {
      this.updateData(parseJwt(this.state.jwt), this.search);
    });
  };

  addPredicate = (data, cb = null) => {
    const pending_predicate = {
      attribute: data.name,
      comparison: null,
      type: data.type,
      value: data.value,
    };

    const new_predicates = this.props.data.segments.concat(pending_predicate);
    const jwtToken = generateJWT(new_predicates);
    // console.log(parseJwt(jwtToken))
    if (cb) cb(jwtToken);
    this.setState({ jwt: jwtToken }, () =>
      this.updateData(parseJwt(this.state.jwt))
    );
  };

  deletePredicate(data) {
    const jwtToken = generateJWT(data);
    this.setState({ jwt: jwtToken }, () =>
      this.updateData(parseJwt(this.state.jwt), this.search)
    );
  }

  search = (page = null) => {
    this.setState({ searching: true });
    // jwt or predicates from segment
    // console.log(this.state.jwt)
    const data = this.state.jwt
      ? parseJwt(this.state.jwt).data
      : this.props.data.segments;
    const predicates_data = {
      data: {
        predicates: data.filter((o) => o.comparison),
      },
    };

    graphql(
      PREDICATES_SEARCH,
      {
        appKey: this.props.app.key,
        search: predicates_data,
        page: page || 1,
      },
      {
        success: (data) => {
          const appUsers = data.predicatesSearch.appUsers;
          this.setState({
            app_users: appUsers.collection,
            meta: appUsers.meta,
            searching: false,
          });
        },
        error: (_error) => {},
      }
    );
  };

  showUserDrawer = (o) => {
    this.props.dispatch(
      toggleDrawer({ userDrawer: true }, () => {
        this.props.dispatch(getAppUser(o.id));
      })
    );
  };

  render() {
    return (
      <div className="mt-4">
        <SegmentManager
          {...this.props}
          loading={this.state.searching}
          predicates={this.props.data.segments}
          meta={this.state.meta}
          collection={this.state.app_users}
          updatePredicate={this.updatePredicate.bind(this)}
          addPredicate={this.addPredicate.bind(this)}
          deletePredicate={this.deletePredicate.bind(this)}
          search={this.search.bind(this)}
          columns={userFormat(this.showUserDrawer, this.props.app)}
          defaultHiddenColumnNames={[
            'id',
            'state',
            'online',
            'lat',
            'lng',
            'postal',
            'browserLanguage',
            'referrer',
            'os',
            'osVersion',
            'lang',
          ]}
          // toggleMapView={this.toggleMapView}
          // map_view={this.state.map_view}
          // enableMapView={true}
        >
          {this.state.jwt ? (
            <Button
              variant={'flat-dark'}
              size={'sm'}
              onClick={this.handleSave}
              className="animate-pulse"
            >
              <i className="fas fa-exclamation-circle mr-2"></i>
              {I18n.t('common.save_changes')}
            </Button>
          ) : null}
        </SegmentManager>
      </div>
    );
  }
}

type CampaignFormProps = {
  match: any;
  app: any;
  campaigns: any;
  mode: string;
  dispatch: (value: any) => void;
  history: any;
  init: any;
};
type CampaignFormState = {
  selected: number;
  data: any;
  tabValue: number;
  deleteDialog: boolean;
};
class CampaignForm extends Component<CampaignFormProps, CampaignFormState> {
  constructor(props) {
    super(props);
    this.state = {
      selected: 0,
      data: {},
      tabValue: 0,
      deleteDialog: false,
    };
  }

  url = () => {
    const id = this.props.match.params.id;
    return `/apps/${this.props.app.key}/campaigns/${id}`;
  };

  componentDidMount() {
    this.fetchCampaign();
  }

  componentDidUpdate(prevProps, _prevState) {
    if (
      this.props.campaigns.campaign === this.state.data.id &&
      this.props.campaigns.ts !== prevProps.campaigns.ts
    ) {
      this.fetchCampaign();
    }
  }

  deleteCampaign = (cb = null) => {
    graphql(
      DELETE_CAMPAIGN,
      {
        appKey: this.props.app.key,
        id: this.state.data.id,
      },
      {
        success: (data) => {
          console.log(data);
          cb && cb();
        },
        error: (error) => {
          console.log(error);
        },
      }
    );
  };

  fetchCampaign = (cb = null) => {
    const id = this.props.match.params.id;

    if (id === 'new') {
      graphql(
        CREATE_CAMPAIGN,
        {
          appKey: this.props.app.key,
          mode: this.props.mode,
          operation: 'new',
          campaignParams: {},
        },
        {
          success: (data) => {
            this.setState(
              {
                data: data.campaignCreate.campaign,
              },
              cb && cb
            );
          },
        }
      );
    } else {
      graphql(
        CAMPAIGN,
        {
          appKey: this.props.app.key,
          mode: this.props.mode,
          id: id,
        },
        {
          success: (data) => {
            this.setState(
              {
                data: data.app.campaign,
              },
              cb && cb
            );
          },
        }
      );
    }
  };

  updateData = (data, cb = null) => {
    this.setState({ data: data }, cb && cb());
  };

  renderEditorForCampaign = () => {
    switch (this.props.mode) {
      case 'tours':
        return (
          <TourManager
            {...this.props}
            url={this.url()}
            updateData={this.updateData}
            data={this.state.data}
          />
        );
      default:
        return (
          <CampaignEditor
            {...this.props}
            //url={this.url()}
            updateData={this.updateData}
            data={this.state.data}
          />
        );
    }
  };

  handleTabChange = (e, i) => {
    this.setState({ tabValue: i });
  };

  tabsContent = () => {
    return (
      <Tabs
        currentTab={this.state.tabValue}
        onChange={this.handleTabChange}
        textColor="inherit"
        tabs={[
          {
            label: I18n.t('campaigns.tabs.stats'),
            content: (
              <CampaignStats
                {...this.props}
                //url={this.url()}
                data={this.state.data}
                getStats={this.getStats}
              />
            ),
          },
          {
            label: I18n.t('campaigns.tabs.settings'),
            content: (
              <CampaignSettings
                {...this.props}
                data={this.state.data}
                mode={this.props.mode}
                successMessage={() =>
                  this.props.dispatch(
                    successMessage(I18n.t('campaigns.campaign_updated'))
                  )
                }
                //url={this.url()}
                updateData={this.updateData}
              />
            ),
          },
          {
            label: I18n.t('campaigns.tabs.audience'),
            content: (
              <CampaignSegment
                {...this.props}
                data={this.state.data}
                //url={this.url()}
                successMessage={() =>
                  this.props.dispatch(
                    successMessage(I18n.t('campaigns.campaign_updated'))
                  )
                }
                updateData={this.updateData}
              />
            ),
          },
          {
            label: I18n.t('campaigns.tabs.editor'),
            content: this.renderEditorForCampaign(),
          },
        ]}
      ></Tabs>
    );
  };

  getStats = (params, cb = null) => {
    graphql(CAMPAIGN_METRICS, params, {
      success: (data) => {
        const d = data.app.campaign;
        cb(d);
      },
      error: (_error) => {},
    });
  };

  isNew = () => {
    return this.props.match.params.id === 'new';
  };

  handleSend = (_e) => {
    const params = {
      appKey: this.props.app.key,
      id: this.state.data.id,
    };

    graphql(DELIVER_CAMPAIGN, params, {
      success: (data) => {
        this.updateData(data.campaignDeliver.campaign, null);
        // this.setState({ status: "saved" })
      },
      error: () => {},
    });
  };

  cloneCampaign = (_e) => {
    const params = {
      appKey: this.props.app.key,
      id: `${this.state.data.id}`,
    };

    graphql(CLONE_MESSAGE, params, {
      success: (_data) => {
        this.props.dispatch(successMessage(I18n.t('campaigns.cloned_success')));

        this.props.init();
      },
      error: () => {
        this.props.dispatch(errorMessage(I18n.t('campaigns.cloned_error')));
      },
    });
  };

  campaignName = (name) => {
    switch (name) {
      case 'campaigns':
        return I18n.t('campaigns.mailing');
      case 'user_auto_messages':
        return I18n.t('campaigns.in_app');
      default:
        return name;
    }
  };

  options = () => [
    {
      title: `${I18n.t('campaigns.pause_title')}`,
      description: I18n.t('campaigns.pause_description'),
      icon: <Pause />,
      id: 'disabled',
      state: 'disabled',
      onClick: this.toggleCampaignState,
    },
    {
      title: I18n.t('campaigns.clone_title'),
      description: I18n.t('campaigns.clone_description'),
      icon: <CopyContentIcon />,
      id: 'enabled',
      state: 'enabled',
      onClick: this.cloneCampaign,
    },
  ];

  toggleCampaignState = () => {
    graphql(
      UPDATE_CAMPAIGN,
      {
        appKey: this.props.app.key,
        id: this.state.data.id,
        campaignParams: {
          state: this.state.data.state === 'enabled' ? 'disabled' : 'enabled',
        },
      },
      {
        success: (data) => {
          this.setState({
            data: data.campaignUpdate.campaign,
          });
          this.props.dispatch(
            successMessage(I18n.t('campaigns.campaign_updated'))
          );
        },
        error: () => {
          this.props.dispatch(errorMessage(I18n.t('campaigns.updated_error')));
        },
      }
    );
  };

  iconMode = (name) => {
    switch (name) {
      case 'campaigns':
        return <EmailIcon />;
      case 'user_auto_messages':
        return <MessageIcon />;
      case 'tours':
        return <FilterFramesIcon />;
      default:
        return name;
    }
  };

  optionsForMailing = () => {
    return [
      /* {
        title: "Preview",
        description: "preview campaign's message",
        icon: <VisibilityRounded />,
        id: "preview",
        onClick: (e) => {
          window.open(
            `${window.location.origin}/apps/${this.props.app.key}/premailer/${this.state.data.id}`,
            "_blank"
          );
        },
      }, */
      {
        title: I18n.t('campaigns.deliver_title'),
        description: I18n.t('campaigns.deliver_description'),
        icon: <SendIcon />,
        id: 'deliver',
        onClick: this.handleSend,
      },
    ];
  };

  deleteOption = () => {
    return {
      title: I18n.t('common.delete'),
      description: I18n.t('campaigns.delete_campaign', {
        name: this.state.data.name,
      }),
      icon: <DeleteOutlineRounded />,
      id: 'delete',
      onClick: this.openDeleteDialog,
    };
  };

  optionsForData = () => {
    let newOptions: any = this.options();
    if (this.props.mode === 'campaigns') {
      newOptions = this.optionsForMailing().concat(this.options());
    }

    newOptions = newOptions.filter((o) => o.state !== this.state.data.state);

    newOptions = newOptions.concat(this.purgeMetricsOptions());

    newOptions.push(this.deleteOption());

    return newOptions;
  };

  purgeMetricsOptions = () => {
    return {
      title: I18n.t('campaigns.purge_title'),
      description: I18n.t('campaigns.purge_description'),
      icon: <ClearAll />,
      id: 'purge',
      onClick: this.purgeMetrics,
    };
  };

  openDeleteDialog = () => {
    this.setState({
      deleteDialog: true,
    });
  };

  purgeMetrics = () => {
    graphql(
      PURGE_METRICS,
      {
        appKey: this.props.app.key,
        id: this.props.match.params.id,
      },
      {
        success: (_data) => {
          this.fetchCampaign(() => {
            this.props.dispatch(successMessage('campaign updated'));
          });
        },
        error: () => {
          this.props.dispatch(errorMessage('error purging metrics'));
        },
      }
    );
  };

  render() {
    const badgeClass = this.state.data.state === 'enabled' ? 'green' : 'gray';

    const title = this.state.data.name
      ? `${this.state.data.name}`
      : this.campaignName(this.props.mode);

    return (
      <div>
        {this.state.deleteDialog && (
          <DeleteDialog
            open={this.state.deleteDialog}
            title={I18n.t('campaigns.delete_campaign', {
              name: title,
            })}
            deleteHandler={() => {
              this.deleteCampaign(() => {
                this.setState(
                  {
                    deleteDialog: false,
                  },
                  () => {
                    this.props.history.push(
                      `/apps/${this.props.app.key}/messages/${this.props.mode}`
                    );
                  }
                );
              });
            }}
          >
            <p>{I18n.t('campaigns.remove_hint')}</p>
          </DeleteDialog>
        )}

        <Content>
          <ContentHeader
            title={
              <div className="justify-around items-center">
                <div className="flex items-center">
                  <div className="mr-2">
                    <div>{this.iconMode(this.props.mode)}</div>
                  </div>

                  {title}
                  <span
                    className={`ml-2 px-2 
                        inline-flex 
                        text-xs 
                        leading-5 
                        font-semibold 
                        rounded-full 
                        bg-${badgeClass}-100 
                        text-${badgeClass}-800`}
                  >
                    {this.state.data.state}
                  </span>
                </div>
              </div>
            }
            actions={
              <React.Fragment>
                <div className="flex items-center space-x-2">
                  {this.props.match.params.id !== 'new' && (
                    <UpgradeButton
                      classes={`
                      absolute z-10 ml-1 mt-3 transform w-screen 
                      max-w-md px-2 origin-top-right right-0
                      md:-ml-4 sm:px-0 lg:ml-0
                      lg:right-2/6 lg:translate-x-1/6`}
                      label={I18n.t('campaigns.activate')}
                      feature="Campaigns"
                    >
                      <SwitchControl
                        label={
                          this.state.data.state === 'disabled'
                            ? I18n.t('campaigns.enables')
                            : I18n.t('campaigns.disables')
                        }
                        setEnabled={this.toggleCampaignState}
                        enabled={this.state.data.state === 'enabled'}
                      ></SwitchControl>

                      {/*<Button
                      className="mr-2"
                      title= "Enable"
                      description={
                        this.state.data.state === 'disabled'
                          ? 'enables the campaign'
                          : 'disables the campaign'
                      }
                      // icon= <CheckCircle />
                      id="enabled"
                      state="enabled"
                      onClick={this.toggleCampaignState}
                    >
                      {
                        this.state.data.state === 'disabled'
                          ? 'Enable'
                          : 'Disable'
                      }

                    </Button>*/}
                    </UpgradeButton>
                  )}

                  {this.props.match.params.id !== 'new' && (
                    <FilterMenu
                      options={this.optionsForData()}
                      value={I18n.t('common.actions')}
                      filterHandler={(option, _closeHandler) => {
                        return option.onClick && option.onClick(option);
                      }}
                      position={'right'}
                    />
                  )}
                </div>
              </React.Fragment>
            }
          />

          {!isEmpty(this.state.data) ? (
            this.isNew() ? (
              <CampaignSettings
                {...this.props}
                data={this.state.data}
                mode={this.props.mode}
                // url={this.url()}
                updateData={this.updateData}
                successMessage={() =>
                  this.props.dispatch(
                    successMessage(I18n.t('campaigns.campaign_updated'))
                  )
                }
              />
            ) : (
              this.tabsContent()
            )
          ) : null}
        </Content>
      </div>
    );
  }
}

type CampaignContainerProps = {
  match: any;
  app: any;
  dispatch: (val: any) => void;
  history: any;
  currentUser: any;
};

type CampaignContainerState = {
  campaigns: any;
  meta: any;
  openDeleteDialog: any;
  loading: boolean;
};
class CampaignContainer extends Component<
  CampaignContainerProps,
  CampaignContainerState
> {
  constructor(props) {
    super(props);
    this.state = {
      campaigns: [],
      meta: {},
      loading: false,
      openDeleteDialog: null,
    };
  }

  componentDidUpdate(prevProps, _prevState) {
    if (
      this.props.match.params.message_type !==
      prevProps.match.params.message_type
    ) {
      this.init();

      this.props.dispatch(setCurrentPage(this.props.match.params.message_type));

      this.props.dispatch(setCurrentSection('Campaigns'));
    }
  }

  componentDidMount() {
    this.props.dispatch(setCurrentSection('Campaigns'));

    this.props.dispatch(setCurrentPage(this.props.match.params.message_type));

    this.init();
  }

  init = (page = null) => {
    this.setState({
      loading: true,
    });

    graphql(
      CAMPAIGNS,
      {
        appKey: this.props.app.key,
        mode: this.props.match.params.message_type,
        page: page || 1,
      },
      {
        success: (data) => {
          const { collection, meta } = data.app.campaigns;
          this.setState({
            campaigns: collection,
            meta: meta,
            loading: false,
          });
        },
      }
    );
  };

  createNewCampaign = (_e) => {
    this.props.history.push(`${this.props.match.url}/new`);
  };

  handleRowClick = (_a, data, _c) => {
    const row = this.state.campaigns[data.dataIndex];
    this.props.history.push(`${this.props.match.url}/${row.id}`);
  };

  renderActions = () => {
    return (
      <div>
        <Button
          color={'primary'}
          onClick={this.createNewCampaign}
          variant="flat-dark"
        >
          {I18n.t('campaigns.create_new')}
        </Button>
      </div>
    );
  };

  deleteCampaign = (id, cb = null) => {
    graphql(
      DELETE_CAMPAIGN,
      {
        appKey: this.props.app.key,
        id: id,
      },
      {
        success: (data) => {
          console.log(data);
          cb && cb();
        },
        error: (error) => {
          console.log(error);
        },
      }
    );
  };

  titleMapping = (kind) => {
    const mapping = {
      banners: I18n.t('navigator.childs.banners'),
      tours: I18n.t('navigator.childs.guided_tours'),
      user_auto_messages: I18n.t('navigator.childs.in_app_messages'),
      campaigns: I18n.t('navigator.childs.mailing_campaigns'),
    };

    return mapping[kind];
  };

  render() {
    return (
      <div className="m-4">
        <Switch>
          <Route
            exact
            path={`${this.props.match.url}/:id`}
            render={(props) => (
              <CampaignForm
                currentUser={this.props.currentUser}
                mode={this.props.match.params.message_type}
                init={this.init}
                {...this.props}
                {...props}
              />
            )}
          />

          <Route
            exact
            path={`${this.props.match.url}`}
            render={(_props) => (
              <Content>
                {this.state.openDeleteDialog && (
                  <DeleteDialog
                    open={this.state.openDeleteDialog}
                    title={I18n.t('campaigns.delete_campaign', {
                      name: this.state.openDeleteDialog.name,
                    })}
                    closeHandler={() => {
                      this.setState({
                        openDeleteDialog: null,
                      });
                    }}
                    deleteHandler={() => {
                      this.deleteCampaign(
                        this.state.openDeleteDialog.id,
                        () => {
                          this.init();
                          this.setState({
                            openDeleteDialog: null,
                          });
                          this.props.dispatch(
                            successMessage(I18n.t('campaigns.remove_success'))
                          );
                        }
                      );
                    }}
                  >
                    <p>{I18n.t('campaigns.remove_hint')}</p>
                  </DeleteDialog>
                )}

                <ContentHeader
                  title={this.titleMapping(
                    this.props.match.params.message_type
                  )}
                  actions={this.renderActions()}
                />

                <Content>
                  {!this.state.loading && this.state.campaigns.length > 0 && (
                    <Table
                      meta={this.state.meta}
                      data={this.state.campaigns}
                      search={this.init.bind(this)}
                      columns={[
                        {
                          field: 'name',
                          title: I18n.t(
                            'definitions.campaigns.campaign_name.label'
                          ),
                          render: (row) =>
                            row && (
                              <div className="flex items-center">
                                <div className="text-lg leading-5 font-bold text-gray-900 dark:text-gray-100">
                                  <AnchorLink
                                    to={`${this.props.match.url}/${row.id}`}
                                  >
                                    {row.name}
                                  </AnchorLink>
                                </div>
                              </div>
                            ),
                        },
                        {
                          field: 'subject',
                          title: I18n.t(
                            'definitions.campaigns.email_subject.label'
                          ),
                        },
                        {
                          field: 'state',
                          title: I18n.t('definitions.campaigns.state.label'),
                          render: (row) => {
                            return (
                              <Badge
                                variant={
                                  row.state === 'enabled' ? 'green' : null
                                }
                              >
                                {I18n.t(`campaigns.state.${row.state}`)}
                              </Badge>
                            );
                          },
                        },
                        {
                          field: 'fromName',
                          title: I18n.t(
                            'definitions.campaigns.from_name.label'
                          ),
                          hidden: true,
                        },
                        {
                          field: 'fromEmail',
                          title: I18n.t(
                            'definitions.campaigns.from_email.label'
                          ),
                          hidden: true,
                        },
                        {
                          field: 'replyEmail',
                          title: I18n.t(
                            'definitions.campaigns.reply_email.label'
                          ),
                          hidden: true,
                        },
                        {
                          field: 'description',
                          title: I18n.t(
                            'definitions.campaigns.description.label'
                          ),
                          hidden: true,
                        },
                        {
                          field: 'timezone',
                          title: 'timezone',
                        },
                        {
                          field: 'scheduledAt',
                          title: I18n.t(
                            'definitions.campaigns.scheduled_at.label'
                          ),
                          hidden: true,
                          type: 'datetime',
                          render: (row) =>
                            row ? (
                              <Moment fromNow>{row.scheduledAt}</Moment>
                            ) : undefined,
                        },
                        {
                          field: 'scheduledTo',
                          title: I18n.t(
                            'definitions.campaigns.scheduled_to.label'
                          ),
                          hidden: true,
                          type: 'datetime',
                          render: (row) =>
                            row ? (
                              <Moment fromNow>{row.scheduledTo}</Moment>
                            ) : undefined,
                        },
                        {
                          field: 'actions',
                          title: I18n.t('definitions.campaigns.actions.label'),
                          render: (row) => (
                            <span
                              className={
                                'px-2 inline-flex text-xs leading-5 font-semibold rounded-full '
                              }
                            >
                              <Button
                                color={'secondary'}
                                variant={'danger'}
                                onClick={() =>
                                  this.setState({
                                    openDeleteDialog: row,
                                  })
                                }
                              >
                                {I18n.t('common.remove')}
                              </Button>
                            </span>
                          ),
                        },
                      ]}
                    ></Table>
                  )}

                  {!this.state.loading && this.state.campaigns.length === 0 ? (
                    <EmptyView
                      title={I18n.t('campaigns.empty.title')}
                      subtitle={<div>{this.renderActions()}</div>}
                    />
                  ) : null}

                  {this.state.loading ? <CircularProgress /> : null}
                </Content>
              </Content>
            )}
          />
        </Switch>
      </div>
    );
  }
}

function mapStateToProps(state) {
  const { auth, app, campaigns } = state;
  const { loading, isAuthenticated } = auth;

  return {
    app,
    loading,
    isAuthenticated,
    campaigns,
  };
}

export default withRouter(connect(mapStateToProps)(CampaignContainer));