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>
{' '}
=>
{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 */