portal/client/components/rawUnits/list/columns.js

import {Meteor} from 'meteor/meteor';
import React, {useState} from 'react';
import dateFormat from '/common/utils/date/toStr';
import rawUnitsTrashedReasons from '/common/info/rawUnit/trashedReasons';
import unitsStatusFlow from '/common/info/unit/statusFlow';
import websiteIcons from '/common/info/website/icons';
import individualTypes from '/common/info/user/types';
import rawUnitsources from '/common/info/rawUnit/sources';
import possessionStatuses from '/common/info/unit/possessionStatuses';
import getPropertyTypeName from '/common/utils/info/getPropertyTypeName';
import getInfoName from '/common/utils/info/getName';
import UserName from '/common/components/users/Name';
import currencify from '/common/utils/currencify';
import RawUnit from '/common/db/rawUnit/collection';
import {RawUnitUnitsList as UnitsList} from '/lib/client/collections';
const {Button, Icon, Modal} = require('/components/generic');
const {Config} = require('/config');
const {UnitTable} = require('/modules/units/client/table');
import Grid from '@material-ui/core/Grid';
import IconButton from '@material-ui/core/IconButton';
import Popover from '@material-ui/core/Popover';
import DeleteIcon from '@material-ui/icons/Delete';
import {makeStyles} from '@material-ui/styles';
const {Input} = require('/components/generic');
import PropTypes from 'prop-types';
import FInput from '/common/components/forms/Input';
import MarkDuplicate from './MarkDuplicate';
import {RawUnitBasicDetails} from '/modules/rawUnits/client/components';
import {Formik, Form} from 'formik';
import {Button as FButton} from '@settlin/formik-mui';
import {useSelector} from 'react-redux';
import RemoveFromBuyer from './utils/RemoveFromBuyer';
import Link from '/common/components/Link';
import useUser from '/common/components/hooks/useUser';
import maskEmailPhone from '/common/utils/maskEmailPhone';
import facings from '/common/info/facings';
import {useMeteorData} from '/common/components/hooks/useMeteorData';
import Loader from '/common/components/Loader';
import LocationFilter from '/common/components/forms/filters/LocationOrProject';

const useStyles = makeStyles({
	listItem: {
		color: 'orangered',
		cursor: 'pointer',
	},
	icButton: {
		padding: '0.3rem',
	},
	icBtnContainer: {
		display: 'inline-block',
		float: 'right',
	},
});
/**
 * Function to trash rawUnit
 * @param {Object} {id, reason} : id of ru and reason selected from Popover
 * @returns {undefined}
 */
const trashRawUnit = ({id, reason}) => Meteor.call('rawUnit.trash', id, {reason}, err => err ? Log.fatal('Failed to delete: ' + err.reason, err) : '');
/**
 *Function to revive rawUnit
 * @param {Object} {event, rawUnitId} : event triggered and ru id
 * @returns {undefined}
 */
const reviveRawUnit = ({event, rawUnitId}) => {
	event.stopPropagation();
	let consent = confirm('Are you sure to revive this rawUnit?');
	if (consent) {
		var rUnit = RawUnit.findOne({_id: rawUnitId}, {defaults: false});
		if (!rUnit) {
			Log.fatal('No such rawUnit');
			return;
		}
		rUnit.revive();
	}
	else {
		return;
	}
};
//Component to show DeleteOption in Status columns
function DeleteOption({o}) {
	const classes = useStyles();
	const [anchorEl, setAnchorEl] = useState(null);

	const handleClick = event => {
		setAnchorEl(event.currentTarget);
	};

	const handleClose = () => {
		setAnchorEl(null);
	};

	const open = Boolean(anchorEl);
	// eslint-disable-next-line no-undefined
	const id = open ? 'simple-popover' : undefined;

	return (
		<Grid className={classes.icBtnContainer}>
			<IconButton aria-label='delete' className={classes.icButton} onClick={handleClick}>
				<DeleteIcon/>
			</IconButton>
			<Popover
				anchorEl={anchorEl}
				anchorOrigin={{
					vertical: 'bottom',
					horizontal: 'left',
				}}
				id={id}
				onClose={handleClose}
				open={open}
				transformOrigin={{
					vertical: 'top',
					horizontal: 'right',
				}}
			>
				<ul className='rawUnitTrashedReasons'>
					{rawUnitsTrashedReasons.map((tr) => (
						<li className={classes.listItem} key={tr.code} onClick={() => trashRawUnit({id: o._id, reason: tr.code})}>
							{tr.name}
						</li>
					))}
				</ul>
			</Popover>
		</Grid>
	);
}
DeleteOption.propTypes = {
	o: PropTypes.object,
};
const hAddDetails = function(data, {setSubmitting}) {
	setSubmitting(true);
	Meteor.call('rawUnit.addNumberEtc', data, (e) => {
		setSubmitting(false);
		if (e) Log.fatal('Failed to update: ' + e.reason, e, data.rawUnitId);
	});
};

// eslint-disable-next-line react/no-multi-comp
function AddPhone({rawUnit: o}) {
	const style = {padding: '2px 8px', marginBottom: '10px'};
	const [processing, setProcessing] = useState(false);
	let locations = useSelector(state => state.locations);

	const hTrash = () => {
		setProcessing(true);
		Meteor.call('rawUnit.trash', o._id, {reason: 'noValidContact'}, function(err) {
			err ? Log.fatal('Failed to trash: ' + err.reason, err) : '';
			setProcessing(false);
		});
	};
	const initialValues = {
		name: o.customer?.name,
		rawUnitId: o._id,
		location: (o.location?.unitLocality !== 'unknownNotDealing') ? (o.detailsByTC?.locality?.value ? o.detailsByTC?.locality : {value: o.location?.locality, label: locations[o.location?.locality]?.name}) : {},
	};
	return (
		<Formik
			initialValues={initialValues}
			onSubmit={hAddDetails}
		>
			{({isValid, isSubmitting}) => (
				<Form autoComplete='off'>
					<Grid container spacing={2}>
						<FInput container={{style, xs: 4}} label='Name' name='name' type='text'/>
						<FInput components={{Field: require('/common/components/forms/filters/Project').default}} container={{style, xs: 8}} label='Project' name='project' type='text'/>
						<FInput container={{style, xs: 12}} helperText='To add multiple phones, use comma eg. 912345678,901234567' label='Phone' multiple name='phone' placeholder='To add multiple phones use comma' required type='text'/>
						<FInput container={{style, xs: 12}} helperText='To add multiple emails, use comma eg. xyx@gmail.com, pqr@gmail.com' label='Email' multiple name='email' placeholder='To add multiple emails use comma' type='text'/>
						<LocationFilter InputProps={{classes: {input: 'mui'}}} container={{xs: 12}} extraParams={{searchProject: false}} label='Location' name='location' required/>

						<Grid container item justifyContent='space-between' style={style} xs={12}>
							<FButton color='secondary' onClick={hTrash} processing={processing} variant='text'>
								Invalid URL/Contact
							</FButton>
							<FButton disabled={!isValid || isSubmitting} processing={isSubmitting} type='submit' variant='outlined'>
								Save
							</FButton>
						</Grid>
					</Grid>
				</Form>
			)}
		</Formik>
	);
}
AddPhone.propTypes = {
	rawUnit: PropTypes.object,
};

/* eslint-disable react/prop-types, react/no-multi-comp */
export default ({showDeleteOption, isReassignPage, isNumbersPage, buyerId, isRawUnitModal, isListPage} = {}) => {
	const locations = useSelector(state => state.locations);
	const user = useUser();
	if (!user) return [];
	const hSubmit = ({data, o}) => {
		// if (!o.assignedTo?.userId) {
		// 	Log.error('Cannot mark as duplicate without a assignee');
		// 	return;
		// }
		Meteor.call('rawUnit.duplicate', {unitId: data.unitId, reason: 'duplicate', rawUnitId: o._id, isListPage: true}, function(err) {
			if (err) Log.fatal(`Failed to mark duplicate: ${err.reason}`, err);
			else Log.success('Sucessfully marked as duplicate');
		});
	};

	return [
		...(
			isReassignPage ? [
				{
					Header: 'Select', accessor: 'select', Cell({original: o}) {
						return (
							<div className='row relative'>
								<Input defaultChecked={isRawUnitModal} label=' ' name='selectedOnes[]' type='checkbox' value={o._id}/>
							</div>
						);
					}, width: 30,
				},
			] : []
		),
		{
			Header: 'Posting Info', accessor: 'saleInfo.postedOn', Cell({original: o}) {
				const {data: listingDestination, isLoading} = useMeteorData(['listingDestination.getAllDestinations']);
				if (isLoading) return <Loader/>;
				const trackingThisRawUnit = !!~(user.rawUnits || []).indexOf(o._id);
				o.customer.phone = (o.customer.phone || []).map(v => maskEmailPhone(v, 'phone'));
				return (
					<div>
						<Link className='underline bold' rel='noopener noreferrer' target='_blank' to={`/rawUnits/process/${o._id}`}>
							{o.identifier}
						</Link>
						<Link className='margin-right-1 underline bold' rel='noopener noreferrer' target='_blank' to={`/rawUnits/edit/${o._id}`}>
							<Icon className='font-inherit' icon={websiteIcons.buttons.edit} title='Edit This'/>
						</Link>
						<Icon className='font-inherit' icon={websiteIcons.shortlist[(o.status || {}).shortlisted ? 'remove' : 'add']} title='Prioritize This RawUnit'/>
						<Icon className='font-inherit' icon={websiteIcons.favorite[trackingThisRawUnit ? 'remove' : 'add']} title='Track This RawUnit'/>
						<br/>
						{o.customer.name}
						{' '}
						{o.saleInfo.postedBy && `(${getInfoName(individualTypes, o.saleInfo.postedBy)})`}
						<span className='hs small'>
							{o.customer.phone?.join(', ')}
						</span>
						<div className='small'>
							{o.saleInfo.group && (
								<div>
									<Link className='underline' rel='noopener noreferrer' target='_blank' to={`/groups/view/${o.saleInfo.group.id}`}>
										{o.saleInfo.group.identifier}
										{' '}
										-
										{o.saleInfo.group.name}
									</Link>
								</div>
							)}
							{o.source.from && (
								// eslint-disable-next-line react/jsx-no-useless-fragment
								<>
									{o.source.url
										? (
											<a className='underline' href={o.source.url.includes('http') ? o.source.url : (listingDestination.find(d => d.code === o.source.from)?.baseUrl || '') + o.source.url} rel='noopener noreferrer' target='_blank'>
												{getInfoName(rawUnitsources, o.source.from)}
											</a>
										)
										: (
											<span>
												{getInfoName(rawUnitsources, o.source.from)}
											</span>
										)}
								</>
							)}
							{o.saleInfo.postedOn && (
								<span className='hs' title='Posted On'>
									(
									{dateFormat(o.saleInfo.postedOn, Config.dateFormats.short)}
									)
								</span>
							)}
							{o.possessionStatus && (
								<span className='hs' title='Possession Status'>
									{getInfoName(possessionStatuses, o.possessionStatus)}
								</span>
							)}
						</div>
					</div>
				);
			},
		},
		{
			Header: 'Details', accessor: 'saleInfo.price.total', Cell({original: o}) {
				return (
					<div>
						<span className='small' title='Type'>
							{getPropertyTypeName(o.propertyType)}
						</span>
						{o.facing && (
							<span className='hs' title='Facing'>
								{getInfoName(facings, o.facing)}
							</span>
						)}
						{Boolean(o.builtUpArea) && (
							<span className='hs' title={'Super BuiltUp Area'}>
								SUB:
								{o.builtUpArea}
							</span>
						)}
						{Boolean(o.plotArea) && (
							<span className='hs'>
								Plot:
								{o.plotArea}
							</span>
						)}
						<br/>
						{o.projectName && (
							<span title='Project'>
								{o.projectName}
							</span>
						)}
						<span className='hs' title='Locality'>
							{(o.location || {}).locality}
							{' '}
							{(o.location || {}).unitLocality && (
								<span>
									{' '}
									=&gt;
									{locations[o.location.unitLocality]?.name}
								</span>
							)}
						</span>
						{(o.location || {}).address && (
							<div className='truncate small' title='Address'>
								{o.location.address}
							</div>
						)}
						<div>
							{Boolean(o.saleInfo.price) && currencify({amount: o.saleInfo.price.total, abbreviated: true})}
							<span className='hs'>
								{o.bedrooms?.number && (
									<>
										{o.bedrooms?.number}
										{' '}
										<Icon className='font-inherit' icon={websiteIcons.spaces.bedroom}/>
									</>
								)}
								{o.bathrooms?.number && (
									<>
										,
										{' '}
										{o.bathrooms?.number}
										{' '}
										<Icon className='font-inherit' icon={websiteIcons.spaces.bathroom}/>
									</>
								)}
							</span>
							{o.facing && (
								<span className='hs' title='Facing'>
									{getInfoName(facings, o.facing)}
								</span>
							)}
						</div>
						{(o.detailsByTC?.bedrooms || o.detailsByTC?.bathrooms || o.detailsByTC?.price) && (
							<div>
								Details by tc :
								{Boolean(o.detailsByTC.price) && currencify({amount: o.detailsByTC.price, abbreviated: true})}
								<span className='hs'>
									{o.detailsByTC?.bedrooms && (
										<>
											{o.detailsByTC?.bedrooms}
											{' '}
											<Icon className='font-inherit' icon={websiteIcons.spaces.bedroom}/>
										</>
									)}
									{o.detailsByTC?.bathrooms && (
										<>
											,
											{' '}
											{o.detailsByTC?.bathrooms}
											{' '}
											<Icon className='font-inherit' icon={websiteIcons.spaces.bathroom}/>
										</>
									)}
								</span>
								{o.detailsByTC.facing && (
									<span className='hs' title='Facing'>
										{	getInfoName(facings, o.detailsByTC.facing)}
									</span>
								)}
							</div>
						)}
					</div>
				);
			},
		},
		...(isNumbersPage
			? [{
				Header: 'Status', accessor: 'updatedAt',
				width: 500,
				Cell({original: o}) { return <AddPhone key={o._id} rawUnit={o}/>; },
			}]
			: [{
				Header: 'Status', accessor: 'updatedAt', Cell({original: o}) {
					const cp = o.processDetails[0];
					const [duplicate, setDuplicate] = useState(false);

					const [openModal, setOpenModal] = useState(false);
					const listTypeOptions = [
						{value: true, label: 'Mark Duplicate'},
					];
					return (
						<div className='row relative'>
							<Modal
								className='teal-text'
								isOpen={openModal}
								onClose={() => setOpenModal(false)}
								style={{maxWidth: '800px'}}
							>
								<Grid className=' s12 m6'>
									<Grid className='card flat indigo lighten-5 indigo-text text-darken-4'>
										<Grid className='card-content'>


											<RawUnitBasicDetails.Edit location={location} rawUnit={o} rawUnitP={o} setOpenModal={setOpenModal} showOnlyCancelRawUnit/>

										</Grid>
									</Grid>
								</Grid>
							</Modal>
							<div className='col s12'>
								{(cp || {}).status !== 'processed' && showDeleteOption && (
									o.cancellation?.flag ?
										<Button className='right' icon={websiteIcons.buttons.refresh} id='revive-rawUnit' onClick={(event) => reviveRawUnit({event, rawUnitId: o._id})} title='Revive-rawUnit'/>
										:
										<DeleteOption o={o}/>
								)}
								{buyerId && <RemoveFromBuyer {...{o, buyerId}}/>}
								{cp && (
									<span>
										{cp.status === 'processed'
											? (
												<span className={`stage-${cp.stage} small`}>
													<Link className='underline small bold blue-text' rel='noopener noreferrer' target='_blank' to={`/units/view/${o.processedUnit?.id}`}>
														{o.processedUnit?.identifier}
													</Link>
													{o.processedUnit && <UnitTable.Status unit={UnitsList.findOne({_id: o.processedUnit.id}) || {}}/>}
												</span>
											)
											: (
												<span className={`stage-${cp.stage}`}>
													{getInfoName(unitsStatusFlow.conversionToUnit, cp.status)}
												</span>
											)
										}
									</span>
								)}
								{o.cancellation?.flag
									? o.cancellation?.temporary
										? (
											<span className='tag'>
												Suspended:
												{getInfoName(rawUnitsTrashedReasons, o.cancellation.status)}
											</span>
										)
										: (
											<span className='cancelled tag'>
												Cancelled -
												{getInfoName(rawUnitsTrashedReasons, o.cancellation.status)}
											</span>
										)
									: ''
								}
								{(o.assignedTo || {}).userId && (
									<div title='Assigned To'>
										<UserName userId={o.assignedTo.userId}/>
									</div>
								)}
								{(o.callInfo || {}).at && (
									<div className={`small truncate call-info status-${o.callInfo.currentStatus}`} title='Last Called On'>
										<UserName userId={o.callInfo.by}/>
										@
										{dateFormat(o.callInfo.at, 'hh:mm A, MMM DD')}
										:
										{o.callInfo.lastRemarks}
									</div>
								)}
								{o.followUp?.at && o.followUp.at < require('/common/utils/date/infinity').infinity && (
									<div className={`small ${o.followUp.at < new Date() ? 'bold red-text' : ''}`} title='Follow Up At'>
										Follow Up:
										{' '}
										{dateFormat(o.followUp.at, 'hh:mm A, MMM DD')}
										{' '}
										-
										{o.followUp.remarks}
									</div>
								)}
								{ o.processDetails[0]?.status !== 'processed' && (
									<Grid item>
										{!duplicate && !isListPage && (
											<FButton label={'Mark Cancellation'} onClick={() =>  setOpenModal(true)   } variant={'outlined'}/>
										)}
										{!duplicate && ((isListPage && !o.cancellation.flag) || (!isListPage && o.cancellation.flag && o.cancellation.status === 'maybeDuplicate')) && (!o.cancellation.flag && !o.cancellation.temporary) && o.processDetails[0]?.status !== 'processed'  &&  <FInput ToggleButtonProps={{selected: duplicate, size: 'small', style: {padding: '0.4rem 0.6rem', fontSize: '0.7rem', color: '#808080'}}} formik={false} onChange={() => setDuplicate(!duplicate)} options={listTypeOptions} size='small' type='buttons'/>}
										{(!o.cancellation.flag || ( o.cancellation.flag && o.cancellation.status === 'maybeDuplicate')) && o.processDetails[0]?.status !== 'processed' && (
											<Formik initialValues={{}} onSubmit={(data) => hSubmit({data, o})}>
												{({setFieldValue}) => (
													<Form>
														{duplicate && (
															<Grid>
																<MarkDuplicate currentRawUnitId={o._id} groupId={o.saleInfo?.group?.id} setDuplicate={setDuplicate} setFieldValue={setFieldValue}/>
																<FButton fab type='submit'/>
															</Grid>
														)}
													</Form>
												)}
											</Formik>
										)}
									</Grid>
								)
								}
							</div>
						</div>
					);
				},
			}]
		),
	];
};
/* eslint-enable react/prop-types, react/no-multi-comp */