TGICS/frontend/src/components/TmUsersSection.jsx

216 lines
7.4 KiB
JavaScript

import { useCallback, useEffect, useMemo, useState } from 'react';
import { Link } from 'react-router-dom';
import { fetchTmUsers } from '../api';
import DashboardLoading from './DashboardLoading';
import exportCsv from './exportCsv';
const SURVEY_ORIGIN = 'https://tgics.cttr.in';
const EMPTY_TOTALS = { tms: 0, contacts_created: 0, doctors_with_surveys: 0, total_surveys: 0 };
function mrWhatsappLink(row) {
const userId = String(row.user_id || '').trim();
if (!userId) {
return { href: '', label: 'Link unavailable' };
}
let digits = String(row.phone || '').replace(/\D+/g, '');
if (digits.length === 10) {
digits = `91${digits}`;
}
if (!digits) {
return { href: '', label: 'No WhatsApp number' };
}
const name = String(row.name || '').trim();
const link = `${SURVEY_ORIGIN}/${userId}`;
const text = `Dear${name ? ` ${name}` : ''},\n\nPlease share this TGICS link with your enrolled doctors. They should open it and enter their WhatsApp mobile number to continue:\n${link}`;
return {
href: `https://api.whatsapp.com/send?phone=${digits}&text=${encodeURIComponent(text)}`,
label: '',
};
}
export default function TmUsersSection({ onUnauthorized }) {
const [items, setItems] = useState([]);
const [totals, setTotals] = useState(EMPTY_TOTALS);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [query, setQuery] = useState('');
const load = useCallback(async (refresh = false) => {
setLoading(true);
setError('');
try {
const res = await fetchTmUsers(refresh);
setItems(Array.isArray(res.data?.items) ? res.data.items : []);
setTotals({ ...EMPTY_TOTALS, ...(res.data?.totals || {}) });
} catch (err) {
if (err.status === 401) {
onUnauthorized?.();
return;
}
setError(err.message || 'Unable to load Territory Managers.');
} finally {
setLoading(false);
}
}, [onUnauthorized]);
useEffect(() => {
load(false);
}, [load]);
const filtered = useMemo(() => {
const q = query.trim().toLowerCase();
if (!q) return items;
return items.filter((row) =>
[row.name, row.employee_code, row.position_name, row.position_code]
.some((v) => String(v || '').toLowerCase().includes(q))
);
}, [items, query]);
const handleExport = () => {
exportCsv(
'tgics_mr_dashboard',
['MR ID', 'Name', 'Employee code', 'Position name', 'Doctors Enrolled', 'Active Doctors', 'Total surveys'],
filtered.map((row) => [
row.user_id,
row.name,
row.employee_code,
row.position_name,
row.contacts_created,
row.doctors_with_surveys,
row.total_surveys,
])
);
};
return (
<>
<div className="dash-stats">
<div className="dash-stat primary">
<small>Total MR Count</small>
<strong>{loading ? '…' : totals.tms}</strong>
</div>
<div className="dash-stat info emphasized">
<small>Total Doctors Enrolled</small>
<strong>{loading ? '…' : totals.contacts_created}</strong>
</div>
<div className="dash-stat warning emphasized">
<small>Active Doctors</small>
<strong>{loading ? '…' : totals.doctors_with_surveys}</strong>
</div>
<div className="dash-stat success">
<small>Total Surveys</small>
<strong>{loading ? '…' : totals.total_surveys}</strong>
</div>
</div>
<main className="dash-card">
<div className="dash-toolbar">
<p className="dash-muted">
{loading
? ''
: query.trim()
? `${filtered.length} of ${items.length} MRs`
: `${items.length} MRs`}
</p>
<div className="dash-toolbar-actions">
<input
type="search"
className="dash-input"
placeholder="Search name, employee code or position"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button type="button" className="dash-btn info" onClick={() => load(true)} disabled={loading}>
Refresh Data
</button>
<button
type="button"
className="dash-btn dark"
onClick={handleExport}
disabled={loading || filtered.length === 0}
>
Export
</button>
</div>
</div>
{error ? <p className="error">{error}</p> : null}
{loading ? <DashboardLoading /> : null}
{!loading && !error && filtered.length === 0 ? (
<p className="dash-muted dash-center">No MRs found.</p>
) : null}
{filtered.length > 0 ? (
<div className="table-wrap">
<table className="dash-table">
<thead>
<tr>
<th>No</th>
<th className="text-left">Name</th>
<th>Employee code</th>
<th>Position name</th>
<th className="dash-col-emphasis">Doctors Enrolled</th>
<th className="dash-col-emphasis">Active Doctors</th>
<th>Total surveys</th>
<th>Doctors</th>
<th>WhatsApp</th>
</tr>
</thead>
<tbody>
{filtered.map((row, index) => {
const whatsapp = mrWhatsappLink(row);
return (
<tr key={row.user_id}>
<td>{index + 1}</td>
<td className="text-left">{row.name || '-'}</td>
<td>{row.employee_code || '-'}</td>
<td>{row.position_name || '-'}</td>
<td className="dash-num dash-col-emphasis">{row.contacts_created}</td>
<td className="dash-num dash-col-emphasis">{row.doctors_with_surveys}</td>
<td className="dash-num">{row.total_surveys}</td>
<td>
{row.contacts_created > 0 ? (
<Link
className="dash-btn info dash-btn-link"
target="_blank"
rel="noopener noreferrer"
to={`/dashboard/doctors?${new URLSearchParams({
mr: row.user_id,
mr_name: row.name,
mr_code: row.employee_code,
})}`}
>
View Doctors
</Link>
) : (
<span className="dash-muted">-</span>
)}
</td>
<td>
{whatsapp.href ? (
<a
className="dash-btn whatsapp dash-btn-link"
href={whatsapp.href}
target="_blank"
rel="noopener noreferrer"
>
Send WhatsApp
</a>
) : (
<span className="dash-muted">{whatsapp.label}</span>
)}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
) : null}
</main>
</>
);
}