User Controller Code Samples

/* eslint-disable consistent-return */
const _ = require('lodash');
const passport = require('passport');
const Joi = require('joi');
const fs = require('fs');
const path = require('path');
const Image = require('../../media/components/image');

const SYSTEM_CONST = require('../../system/constants');

/**
 * Create a new user
 * Using by Administrator
 */
exports.create = async (req, res, next) => {
  try {
    const schema = Joi.object().keys({
      username: Joi.string().required(),
      phoneNumber: Joi.string().optional(),
      role: Joi.string().valid(['admin', 'user']).default('user').required(),
      type: Joi.string().valid(['user', 'model']).default('user').required(),
      email: Joi.string().email().required(),
      password: Joi.string().min(6).required(),
      availableToken: Joi.number().min(0).allow([null]).optional(),
      address: Joi.string().allow([null, '']).optional(),
      state: Joi.string().allow([null, '']).optional(),
      city: Joi.string().allow([null, '']).optional(),
      country: Joi.string().allow([null, '']).optional(),
      isActive: Joi.boolean().allow([null]).default(true).optional(),
      avatar: Joi.string().allow([null, '']).optional(),
      emailVerified: Joi.boolean().allow([null]).default(true).optional(),
      isCompletedProfile: Joi.boolean().allow([null]).default(true).optional(),
      isBlocked: Joi.boolean().allow([null]).default(true).optional()
    });

    const validate = Joi.validate(req.body, schema);
    if (validate.error) {
      return next(PopulateResponse.validationError(validate.error));
    }

    if (validate.value.role === 'admin' && !validate.value.password) {
      return next(
        PopulateResponse.validationError({ msg: 'Admin accounnt needs password to login, please enter password!' })
      );
    }

    const user = await Service.User.create(validate.value);
    res.locals.user = user;
    return next();
  } catch (e) {
    return next(e);
  }
};

/**
 * do update for admin update
 */
exports.update = async (req, res, next) => {
  try {
    const user = req.params.id ? await DB.User.findOne({ _id: req.params.id }) : req.user;
    let publicFields = ['address', 'phoneNumber', 'isActive', 'avatar', 'email', 'isBlocked'];
    if (req.user.role === 'admin') {
      publicFields = publicFields.concat(['isCompletedProfile', 'emailVerified', 'role', 'username', 'availableToken']);
      req.body.password && (publicFields = publicFields.concat(['password']));
    }
    const fields = _.pick(req.body, publicFields);
    _.merge(user, fields);
    if (user.type === 'user') {
      user.isApproved = true;
    }
    await user.save();

    res.locals.update = user;
    next();
  } catch (e) {
    next(e);
  }
};

exports.me = (req, res, next) => {
  res.locals.me = req.user.getPublicProfile();
  next();
};

exports.findOne = async (req, res, next) => {
  try {
    const user = await DB.User.findOne({
      _id: req.params.id
    });
    res.locals.user = user;
    next();
  } catch (e) {
    next(e);
  }
};

/**
 * find user from Add Contact Page
 */
exports.findByUsername = async (req, res, next) => {
  try {
    const schema = Joi.object().keys({
      username: Joi.string().required()
    });

    const validate = Joi.validate(req.params, schema);
    if (validate.error) {
      return next(PopulateResponse.validationError(validate.error));
    }

    const query = _.merge(validate.value, {
      type: { $ne: req.user.type },
      isCompletedProfile: true,
      isApproved: true,
      isActive: true,
      isBlocked: false
    });
    const user = await DB.User.findOne(query);
    if (!user) {
      return next(PopulateResponse.notFound({ message: 'User is not found' }));
    }

    const contact = await DB.Contact.findOne({
      $or: [
        { addedBy: req.user._id, userId: user._id },
        { addedBy: user._id, userId: req.user._id }
      ]
    });
    res.locals.user = { ...user.getPublicProfile(), isFriend: contact ? true : false, contactId: contact?._id || null };
    return next();
  } catch (e) {
    return next(e);
  }
};

/**
 * update user avatar
 */
exports.updateAvatar = async (req, res, next) => {
  try {
    const user = req.params.id ? await DB.User.findOne({ _id: req.params.id }) : req.user;
    if (!user) {
      return next(PopulateResponse.notFound());
    }

    const avatarSize = await DB.Config.findOne({ key: SYSTEM_CONST.AVATAR_SIZE });
    if (!avatarSize || !avatarSize.value || !avatarSize.value.width || !avatarSize.value.height) {
      return PopulateResponse.serverError({ msg: 'Missing avatar size!' });
    }
    // create thumb for the avatar
    const thumbPath = await Image.resize({
      input: req.file.path,
      width: avatarSize.value.width || 250,
      height: avatarSize.value.height || 250,
      resizeOption: '^'
    });

    await DB.User.update({ _id: req.params.id || req.user._id }, { $set: { avatar: thumbPath } });

    // unlink old avatar
    if (user.avatar && !Helper.String.isUrl(user.avatar) && fs.existsSync(path.resolve(user.avatar))) {
      fs.unlinkSync(path.resolve(user.avatar));
    }
    // remove tmp file
    // if (fs.existsSync(path.resolve(req.file.path))) {
    //   fs.unlinkSync(path.resolve(req.file.path));
    // }

    res.locals.updateAvatar = {
      url: DB.User.getAvatarUrl(thumbPath)
    };
    return next();
  } catch (e) {
    return next(e);
  }
};

exports.search = async (req, res, next) => {
  const page = Math.max(0, req.query.page - 1) || 0; // using a zero-based page index for use with skip()
  const take = parseInt(req.query.take, 10) || 10;

  try {
    let query = Helper.App.populateDbQuery(req.query, {
      text: ['phoneNumber', 'email', 'username'],
      boolean: ['isOnline', 'isApproved', 'isCompletedProfile', 'isCompletedDocument', 'isActive', 'isBlocked'],
      equal: ['role', 'type', 'gender', 'city', 'state', 'country']
    });

    if (req.user.role !== 'admin') {
      query = {
        ...query,
        isApproved: true,
        isCompletedProfile: true,
        isActive: true,
        isBlocked: false
      };
    }

    const sort = Helper.App.populateDBSort(req.query);
    const count = await DB.User.count(query);
    const items = await DB.User.find(query)
      .collation({ locale: 'en' })
      .sort(sort)
      .skip(page * take)
      .limit(take)
      .exec();

    res.locals.search = {
      count,
      items: await checkAndConvertFriend(items, req.user)
    };
    next();
  } catch (e) {
    next(e);
  }
};

exports.searchFriends = async (req, res, next) => {
  const page = Math.max(0, req.query.page - 1) || 0; // using a zero-based page index for use with skip()
  const take = parseInt(req.query.take, 10) || 10;
  try {
    let query = Helper.App.populateDbQuery(req.query, {
      text: ['phoneNumber', 'email', 'username'],
      boolean: ['isOnline', 'isApproved', 'isCompletedProfile', 'isCompletedDocument', 'isActive', 'isBlocked'],
      equal: ['role', 'type', 'gender', 'city', 'state', 'country']
    });

    if (req.user.role !== 'admin') {
      query = {
        ...query,
        isApproved: true,
        isCompletedProfile: true,
        isActive: true,
        isBlocked: false
      };
    }

    const sort = Helper.App.populateDBSort(req.query);
    const items = await DB.User.find(query)
      .collation({ locale: 'en' })
      .sort(sort)
      .exec();

    // add user response and check for friend
    const newItems = await checkAndConvertFriend(items, req.user);
    const data = newItems.filter((i) => i.isFriend);
    res.locals.search = {
      count: data.length,
      items: data.slice(page * take, (page + 1) * take )
    };
    next();
  } catch (e) {
    next(e);
  }
};

async function checkAndConvertFriend(models, user) {
  const query = {
    $or: [
      { userId: user._id, addedBy: { $in: models } },
      { userId: { $in: models }, addedBy: user._id }
    ]
  };
  const contacts = await DB.Contact.find(query);
  const array = models.map(model => {
    let data = user?.role === 'admin' ? model : model.getPublicProfile();
    const isFriend = contacts.find(
      contact =>
        contact.userId.toString() === model._id.toString() || contact.addedBy.toString() === model._id.toString()
    );

    data.isFriend = isFriend ? true : false;
    return data;
  });
  return array;
}

exports.remove = async (req, res, next) => {
  try {
    const user = DB.User.findOne({ _id: req.params.userId });
    if (!user) {
      return next(PopulateResponse.notFound());
    }

    if (user.role === 'admin') {
      return next(PopulateResponse.forbidden());
    }

    // permanently delete
    // contact
    await DB.Contact.deleteMany({
      $or: [{ addedBy: req.params.userId }, { userId: req.params.userId }]
    });
    // conversation
    await DB.Conversation.deleteMany({ memberIds: req.params.userId });
    // conversation meta
    await DB.ConversationUserMeta.deleteMany({ userId: req.params.userId });
    // message
    await DB.Message.deleteMany({
      $or: [{ senderId: req.params.userId }, { recipientId: req.params.userId }]
    });
    // device
    await DB.Device.deleteMany({ userId: req.params.userId });
    // invoice
    await DB.Invoice.deleteMany({ userId: req.params.userId });
    // transaction
    await DB.Transaction.deleteMany({ userId: req.params.userId });
    // payout
    await DB.PayoutRequest.deleteMany({ modelId: req.params.userId });
    // purchase item
    const purchaseItems = await DB.PurchaseItem.find({ userId: req.params.userId }).exec();
    if (user.type === 'model') {
      // sell item - not remove purchase item
      const sellItemIds = purchaseItems.map(i => i.sellItemId);
      await DB.SellItem.deleteMany({
        $and: [{ userId: req.params.userId }, { _id: { $nin: sellItemIds } }]
      });

      // earning
      await DB.Earning.deleteMany({ modelId: req.params.userId });
    }
    // media - not remove purchase item
    const mediaIds = purchaseItems.map(i => i.mediaId);
    await DB.Media.deleteMany({
      $and: [{ ownerId: req.params.userId }, { _id: { $nin: mediaIds } }]
    });
    await DB.PurchaseItem.deleteMany({ userId: req.params.userId });
    // share love
    await DB.ShareLove.deleteMany({
      $or: [{ userId: req.params.userId }, { modelId: req.params.userId }]
    });
    // phone verify
    await DB.VerifyCode.deleteMany({ userId: req.params.userId });
    // user social
    // await DB.UserSocial.deleteMany({ userId: req.params.userId });
    await user.remove();
    res.locals.remove = { success: true };
    return next();
  } catch (e) {
    return next(e);
  }
};

exports.updateProfile = async (req, res, next) => {
  try {
    const schema = Joi.object().keys({
      username: Joi.string().min(3).required(),
      gender: Joi.string().allow(['male', 'female', 'transgender']).required(),
      bio: Joi.string().min(6).required(),
      age: Joi.number().min(0).required(),
      address: Joi.string().allow(['', null]).optional(),
      city: Joi.string().allow(['', null]).optional(),
      state: Joi.string().allow(['', null]).optional(),
      country: Joi.string().allow(['', null]).optional(),
      phoneNumber: Joi.string().allow(['', null]).optional(),
      email: Joi.string().email().required()
    });

    const validate = Joi.validate(req.body, schema);
    if (validate.error) {
      return next(PopulateResponse.validationError(validate.error));
    }

    const user = await DB.User.findOne({ _id: req.user._id }); //? User update profile

    if (!user) {
      return next(PopulateResponse.error({ msg: 'User is not found!' }));
    }

    const username = validate.value.username.toLowerCase().trim();
    const email = validate.value.email.trim();
    const count = await DB.User.count({ $or: [{ username }, { email }], _id: { $ne: user._id } });

    if (count) {
      return next(PopulateResponse.error({ msg: 'This username or email has been taken!' }));
    }

    _.merge(user, validate.value);

    await user.save();
    const isCompletedProfile = await Service.User.updateCompletedProfile(user);
    user.isCompletedProfile = isCompletedProfile.success;
    res.locals.update = user.getPublicProfile();
    next();
  } catch (e) {
    return next(e);
  }
};

exports.updateDocument = async (req, res, next) => {
  try {
    const schema = Joi.object().keys({
      address: Joi.string().required(),
      city: Joi.string().required(),
      state: Joi.string().required(),
      country: Joi.string().required(),
      firstName: Joi.string().required(),
      lastName: Joi.string().required(),
      birthday: Joi.string().required(),
      instagram: Joi.string().allow([null, '']).optional(),
      twitter: Joi.string().allow([null, '']).optional(),
      number: Joi.string().required(),
      type: Joi.string().allow(['passport', 'ID', 'driverCard']).required(),
      zipCode: Joi.string().required(),
      isConfirm: Joi.boolean().required(),
      isExpired: Joi.boolean().allow([null, '']).default(false).optional(),
      expiredDate: Joi.string().allow([null, '']).optional(),
      isApproved: Joi.boolean().optional() //? admin approve the document
    });

    const validate = Joi.validate(req.body, schema);
    if (validate.error) {
      return next(PopulateResponse.validationError(validate.error));
    }
    const query = {
      _id: req.user.role === 'admin' ? req.params.id : req.user._id
    };
    const user = await DB.User.findOne(query);
    if (!user) {
      return next(PopulateResponse.notFound());
    }

    user.verificationDocument = Object.assign(user.verificationDocument, _.omit(validate.value, ['isApproved']));
    user.isCompletedDocument = true;
    if (req.user.role === 'admin') {
      user.isApproved = validate.value.isApproved || false;
    }
    await user.save();
    res.locals.document = user.verificationDocument;
    next();
  } catch (e) {
    return next(e);
  }
};

exports.updateTokenPerMessage = async (req, res, next) => {
  try {
    const schema = Joi.object().keys({
      token: Joi.number().min(1).required()
    });

    const validate = Joi.validate(req.body, schema);
    if (validate.error) {
      return next(PopulateResponse.validationError(validate.error));
    }

    if (req.user.type !== 'model') {
      return next(PopulateResponse.forbidden({ message: 'Only models can update!' }));
    }

    req.user.tokenPerMessage = validate.value.token;
    await req.user.save();
    res.locals.tokenPerMessage = req.user;
    return next();
  } catch (e) {
    return next(e);
  }
};

exports.getOTP = async (req, res, next) => {
  try {
    const code = process.env.PHONE_DEBUG ? '0000' : Helper.String.randomString(4, '1234567890');
    let data = await DB.VerifyCode.findOne({ email: req.user.email });
    if (!data) {
      data = new DB.VerifyCode({ userId: req.user._id, email: req.user.email });
    }
    data.code = code;
    await data.save();

    const siteName = await DB.Config.findOne({ key: SYSTEM_CONST.SITE_NAME });
    // send mail with verify code to user
    await Service.Mailer.send('verify-code-email.html', req.user.email, {
      subject: 'Your verify code',
      verifyCode: code.toString(),
      siteName: siteName?.value || 'XChat'
    });

    res.locals.getOTP = PopulateResponse.success({ message: 'Send OTP is successfully!' }, 'OTP_SENT');
    return next();
  } catch (e) {
    return next(e);
  }
};

/**
 * update model certification photo
 */
exports.updateCertificationPhoto = async (req, res, next) => {
  try {
    const user = req.params.id
      ? await DB.User.findOne({
          _id: req.params.id,
          type: 'model' // only model to update certification
        })
      : req.user;
    if (!user) {
      return next(PopulateResponse.notFound());
    }

    const certificationSize = await DB.Config.findOne({ key: SYSTEM_CONST.CERTIFICATION_SIZE });
    if (
      !certificationSize ||
      !certificationSize.value ||
      !certificationSize.value.width ||
      !certificationSize.value.height
    ) {
      return PopulateResponse.serverError({ msg: 'Missing certification size!' });
    }

    // create thumb for the certification
    const thumbPath = await Image.resize({
      input: req.file.path,
      width: certificationSize.value.width || 250,
      height: certificationSize.value.height || 250,
      resizeOption: '^'
    });
    const updateString = `verificationDocument.${req.query.position}`;
    const update = {
      [updateString]: thumbPath
    };

    await DB.User.update(
      {
        _id: req.params.id || req.user._id
      },
      {
        $set: update
      }
    );
    // unlink old certification
    if (
      user.verificationDocument &&
      user.verificationDocument[req.query.position] &&
      !Helper.String.isUrl(user.verificationDocument[req.query.position]) &&
      fs.existsSync(path.resolve(user.verificationDocument[req.query.position]))
    ) {
      fs.unlinkSync(path.resolve(user.verificationDocument[req.query.position]));
    }

    // remove tmp file
    // if (fs.existsSync(path.resolve(req.file.path))) {
    //   fs.unlinkSync(path.resolve(req.file.path));
    // }

    res.locals.updateCertificationPhoto = {
      url: DB.User.getAvatarUrl(update[updateString]) // convert to string
    };
    return next();
  } catch (e) {
    return next(e);
  }
};

/**
 * User update password
 */
exports.updatePassword = async (req, res, next) => {
  const schema = Joi.object().keys({
    email: Joi.string().email().required(),
    password: Joi.string().min(6).required(),
    newPassword: Joi.string().min(6).required()
  });

  const validate = Joi.validate(req.body, schema);
  if (validate.error) {
    return next(PopulateResponse.validationError(validate.error));
  }

  try {
    passport.authenticate('local', async (err, user, info) => {
      const error = err || info;
      if (error) {
        return next(error);
      }
      if (!user) {
        return next(PopulateResponse.notFound());
      }

      user.password = validate.value.newPassword;
      await user.save();

      res.locals.updatePassword = {
        success: true
      };
      return next();
    })(req, res, next);
  } catch (e) {
    return next(e);
  }
};

/**
 * User deactive account yourself
 */
exports.deactiveAccount = async (req, res, next) => {
  try {
    const user = req.user;
    user.isBlocked = true;
    await user.save();

    res.locals.deactive = PopulateResponse.success(
      { message: 'Your account has been deactived, you will be logged out.' },
      'USER_DEACTIVED'
    );
    next();
  } catch (e) {
    next(e);
  }
};

Model Details Code Samples

import * as React from 'react';
import Head from 'next/head';
import { connect } from 'react-redux';
import { withAuth } from 'lib/withAuth';
import withReduxSaga from 'lib/withReduxSaga';
import { toast } from 'react-toastify';
import Router from 'next/router';
// Actions
import { findContact, resetFindContactStore } from 'lib/contact/actions';
import { loadUser } from 'lib/user/actions';
// Child components
import ContactHeader from 'components/contact/contact-detail-box/header';
import ContactContent from 'components/contact/contact-detail-box/content';
import ContactSearchForm from 'components/contact/contact-search-form';
import UserListing from 'components/user/user-listing';
import UserFilter from 'components/user/filter/user-filter';
import LocationSubFilter from 'components/user/filter/location-sub-filter';

interface IProps {
  authUser: any;

  addContactStore: {
    requesting: boolean;
    success: boolean;
    error: any;
  };

  resetFindContactStore: Function;
  findContact: Function;
  findContactStore: {
    requesting: boolean;
    success: boolean;
    error: any;
    contact: any;
    isFriend: boolean;
  };

  removeContact: Function;
  removeContactStore: {
    requesting: boolean;
    success: boolean;
    error: any;
  };

  shareLoveStore: {
    requesting: boolean;
    success: boolean;
    error: any;
  };

  createConvStore: {
    requesting: boolean;
    success: boolean;
    error: any;
    data: any;
  };

  loadUser: Function;
  loadUserStore: {
    requesting: boolean;
    success: boolean;
    error: any;
  };
}

interface IState {
  isShowLocation: boolean;
  gender: string;
  country: string;
  state: string;
  city: string;
}

class ModelListing extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      isShowLocation: false,
      gender: '',
      country: '',
      state: '',
      city: ''
    };
  }

  componentDidMount() {
    this.props.resetFindContactStore();
  }

  componentDidUpdate(prevProps: IProps) {
    const { addContactStore, findContactStore, removeContactStore, shareLoveStore, createConvStore, loadUserStore } =
      this.props;

    //? handle find contact store (only hanlde error)
    if (
      prevProps.findContactStore.requesting &&
      !findContactStore.requesting &&
      !findContactStore.success &&
      findContactStore.error
    ) {
      return toast.error(findContactStore.error?.data?.message || 'User is not found');
    }
    //? --- end ---

    //? handle add contact store
    if (
      prevProps.addContactStore.requesting &&
      !addContactStore.requesting &&
      addContactStore.success &&
      !addContactStore.error
    ) {
      return toast.success('Added to your favorites');
    }
    if (
      prevProps.addContactStore.requesting &&
      !addContactStore.requesting &&
      !addContactStore.success &&
      addContactStore.error
    ) {
      return toast.error(addContactStore.error?.data?.message || 'Add to favorites failed!');
    }
    //? --- end ---

    //? handle remove contact store
    if (
      prevProps.removeContactStore.requesting &&
      !removeContactStore.requesting &&
      removeContactStore.success &&
      !removeContactStore.error
    ) {
      return toast.success('Removed from your favorites');
    }
    if (
      prevProps.removeContactStore.requesting &&
      !removeContactStore.requesting &&
      !removeContactStore.success &&
      removeContactStore.error
    ) {
      return toast.error(removeContactStore.error?.data?.message || 'Remove from favorites failed!');
    }
    //? --- end ---

    //? handle share love store
    if (
      prevProps.shareLoveStore.requesting &&
      !shareLoveStore.requesting &&
      shareLoveStore.success &&
      !shareLoveStore.error
    ) {
      return toast.success('Tip sent successfully!');
    }
    if (
      prevProps.shareLoveStore.requesting &&
      !shareLoveStore.requesting &&
      !shareLoveStore.success &&
      shareLoveStore.error
    ) {
      return toast.error(shareLoveStore.error?.data?.message || 'Show love fail!');
    }
    //? --- end ---

    //? handle create conversation store
    if (
      prevProps.createConvStore.requesting &&
      !createConvStore.requesting &&
      createConvStore.success &&
      !createConvStore.error &&
      createConvStore.data
    ) {
      Router.push('/message/' + createConvStore.data?._id);
      return;
    }
    if (
      prevProps.createConvStore.requesting &&
      !createConvStore.requesting &&
      !createConvStore.success &&
      createConvStore.error
    ) {
      return toast.error(createConvStore.error?.data?.message || 'Create conversation fail!');
    }
    //? --- end ---

    //? handle load user store (only handle error)
    if (
      prevProps.loadUserStore.requesting &&
      !loadUserStore.requesting &&
      !loadUserStore.success &&
      loadUserStore.error
    ) {
      return toast.error(loadUserStore.error?.data?.message || 'Load user fail!');
    }
    //? --- end ---
  }

  async loadUser(query: any) {
    const { gender, country, state, city } = this.state;
    this.props.loadUser({ ...query, type: 'model', gender, country, state, city });
  }

  checkProfile = (username: string ) => {
    // if (!isFriend) {
    //   return toast.error('You must add this model to favorite to view his/her profile');
    // }
    Router.push(
      { pathname: '/contact/detail', query: { username } },
      '/contact/detail/'
    );
  }

  render() {
    const { findContactStore, authUser } = this.props;
    const { isShowLocation } = this.state;
    return (
      <React.Fragment>
        <Head>
          <title>Models Listing</title>
        </Head>
        <main className="main scroll">
          <div className="chats">
            <div className="chat-body p-3">
              <div className="row m-0 ">
                <div className="col-md-4 col-xs-12">
                  <h4 className="font-weight-semibold">Models listing</h4>
                </div>
                <div className="col-md-8 col-xs-12 mb-2">
                  <div className="search-filter">
                    {authUser.type === 'user' && (
                      <UserFilter onFilter={this.loadUser.bind(this)} isShowLocation={this.setState.bind(this)} />
                    )}
                    <ContactSearchForm findContact={this.props.findContact.bind(this)} />
                  </div>
                </div>
                {authUser.type === 'user' && isShowLocation && (
                  <div className="col-md-12 align-self-end mb-2">
                    <div className="search-filter location-filter">
                      <LocationSubFilter onFilter={this.loadUser.bind(this)} onLocation={this.setState.bind(this)} />
                    </div>
                  </div>
                )}
                {findContactStore.contact && (
                  <div className="col-md-12 col-12 mt-2">
                    <div className="container-xl p-0">
                      <ContactHeader contact={findContactStore.contact} isFriend={findContactStore.isFriend} />
                      <div className="row friends-info">
                        <div className="col">
                          <ContactContent contact={findContactStore.contact} />
                        </div>
                      </div>
                    </div>
                  </div>
                )}
              </div>
              <UserListing loadMoreUser={this.loadUser.bind(this)} checkProfile={this.checkProfile.bind(this)} />
            </div>
          </div>
        </main>
      </React.Fragment>
    );
  }
}

const mapStatetoProps = (state: any) => {
  const { shareLoveStore, addContactStore, findContactStore, removeContactStore } = state.contact;

  return {
    shareLoveStore,
    addContactStore,
    findContactStore,
    removeContactStore,
    createConvStore: state.conversation.createConvStore,
    ...state.user,
    authUser: state.auth.authUser
  };
};
const mapDispatch = {
  findContact,
  loadUser,
  resetFindContactStore
};

export default withReduxSaga(withAuth(connect(mapStatetoProps, mapDispatch)(ModelListing))) as any;