updates on the redesign page for all the pages
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState, useRef, useMemo } from 'react';
|
||||
import TitleCard from 'components/nearle_components/TitleCard';
|
||||
import React, { useEffect, useState, useRef, useMemo, Fragment } from 'react';
|
||||
import MainCard from 'components/MainCard';
|
||||
import axios from 'axios';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
@@ -40,26 +39,32 @@ import {
|
||||
DialogTitle,
|
||||
FormLabel,
|
||||
TablePagination,
|
||||
Chip,
|
||||
Skeleton
|
||||
Skeleton,
|
||||
Avatar,
|
||||
Paper
|
||||
} from '@mui/material';
|
||||
import {
|
||||
EyeOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EditOutlined,
|
||||
IssuesCloseOutlined,
|
||||
StopOutlined
|
||||
StopOutlined,
|
||||
CloseOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { PopupTransition } from 'components/@extended/Transitions';
|
||||
import { FaRegCheckCircle } from 'react-icons/fa';
|
||||
import { TbBrandDatabricks } from 'react-icons/tb';
|
||||
import { GiMoneyStack } from 'react-icons/gi';
|
||||
import { FiUser } from 'react-icons/fi';
|
||||
import { FaRegAddressCard } from 'react-icons/fa';
|
||||
import { GiModernCity } from 'react-icons/gi';
|
||||
import { MdNumbers } from 'react-icons/md';
|
||||
import { TbWorldLongitude } from 'react-icons/tb';
|
||||
import { FiPhoneCall } from 'react-icons/fi';
|
||||
import { FaRegCheckCircle, FaRegAddressCard } from 'react-icons/fa';
|
||||
import { TbBrandDatabricks, TbWorldLongitude, TbWorldLatitude } from 'react-icons/tb';
|
||||
import { GiMoneyStack, GiModernCity } from 'react-icons/gi';
|
||||
import { FiUser, FiPhoneCall } from 'react-icons/fi';
|
||||
import {
|
||||
MdNumbers,
|
||||
MdGroups,
|
||||
MdCheckCircle,
|
||||
MdHourglassEmpty,
|
||||
MdCancel,
|
||||
MdMyLocation,
|
||||
MdPersonPin
|
||||
} from 'react-icons/md';
|
||||
import { LuMail } from 'react-icons/lu';
|
||||
import { BiUser } from 'react-icons/bi';
|
||||
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
||||
@@ -68,6 +73,97 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { getalltenants, gettenantsummary } from 'pages/api/api';
|
||||
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
|
||||
|
||||
// ============================================================================
|
||||
// Design tokens — shared with the deliveries page so every surface (header,
|
||||
// filters, KPI tiles, tabs, badges, dialogs) speaks the same visual language.
|
||||
// ============================================================================
|
||||
const DT = {
|
||||
radiusPill: 999,
|
||||
radiusCard: 16,
|
||||
radiusInner: 12,
|
||||
shadowSoft: '0 14px 40px rgba(15, 23, 42, 0.10)',
|
||||
shadowMd: '0 8px 24px rgba(15, 23, 42, 0.08)',
|
||||
shadowPop: '0 18px 50px rgba(15, 23, 42, 0.18)',
|
||||
textPrimary: '#0f172a',
|
||||
textSecondary: '#64748b',
|
||||
textMuted: '#94a3b8',
|
||||
borderSubtle: '#e2e8f0',
|
||||
divider: '#f1f5f9',
|
||||
surface: '#ffffff',
|
||||
surfaceAlt: '#f8fafc'
|
||||
};
|
||||
|
||||
const a = (c, suffix) => `${c}${suffix}`;
|
||||
const tint = (c) => a(c, '08');
|
||||
const soft = (c) => a(c, '18');
|
||||
const ring = (c) => a(c, '26');
|
||||
const edge = (c) => a(c, '55');
|
||||
|
||||
const pillFieldSx = (color) => ({
|
||||
cursor: 'pointer',
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: DT.radiusPill + 'px',
|
||||
bgcolor: tint(color),
|
||||
fontWeight: 600,
|
||||
color: DT.textPrimary,
|
||||
paddingRight: '8px',
|
||||
cursor: 'pointer',
|
||||
transition: 'border-color 0.15s, box-shadow 0.15s, background-color 0.2s',
|
||||
'& fieldset': { borderColor: edge(color), borderWidth: 1.5 },
|
||||
'&:hover fieldset': { borderColor: color },
|
||||
'&.Mui-focused': { boxShadow: `0 0 0 3px ${ring(color)}` },
|
||||
'&.Mui-focused fieldset': { borderColor: color, borderWidth: 2 }
|
||||
},
|
||||
'& .MuiAutocomplete-endAdornment .MuiSvgIcon-root': { color: color }
|
||||
});
|
||||
|
||||
// Status palette — drives the pill tabs and per-row badges.
|
||||
const STATUS_META = {
|
||||
active: { label: 'Active', color: '#10b981', icon: MdCheckCircle, statusKey: 'active' },
|
||||
pending: { label: 'Pending', color: '#f59e0b', icon: MdHourglassEmpty, statusKey: 'pending' },
|
||||
inactive: { label: 'Inactive', color: '#ef4444', icon: MdCancel, statusKey: 'inactive' }
|
||||
};
|
||||
|
||||
const STATUS_TABS = [
|
||||
{ status: 'active', countKey: 'active', tabStatus: 'Active' },
|
||||
{ status: 'pending', countKey: 'pending', tabStatus: 'Pending' },
|
||||
{ status: 'inactive', countKey: 'inactive', tabStatus: 'InActive' }
|
||||
];
|
||||
|
||||
const KPI_META = [
|
||||
{ key: 'active', label: 'Active Tenants', color: '#10b981', icon: MdCheckCircle, countKey: 'active' },
|
||||
{ key: 'pending', label: 'Pending Approval', color: '#f59e0b', icon: MdHourglassEmpty, countKey: 'pending' },
|
||||
{ key: 'inactive', label: 'Inactive Tenants', color: '#ef4444', icon: MdCancel, countKey: 'inactive' }
|
||||
];
|
||||
|
||||
const SoftPaper = (props) => (
|
||||
<Paper
|
||||
{...props}
|
||||
sx={{
|
||||
mt: 0.75,
|
||||
borderRadius: 2,
|
||||
boxShadow: DT.shadowPop,
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const AccentAvatar = ({ color, selected, size = 24, children }) => (
|
||||
<Avatar
|
||||
sx={{
|
||||
width: size,
|
||||
height: size,
|
||||
bgcolor: selected ? color : soft(color),
|
||||
color: selected ? '#fff' : color,
|
||||
transition: 'background-color 0.15s, color 0.15s'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Avatar>
|
||||
);
|
||||
|
||||
// ==============================|| Starts here||============================== //
|
||||
const Clients1 = () => {
|
||||
const textFieldRef = useRef(null);
|
||||
@@ -474,114 +570,356 @@ const Clients1 = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const activeTabMeta = STATUS_META[STATUS_TABS[value0]?.status] || STATUS_META.active;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{(getalltenantsIsLoading || summaryDataIsLoading || isloader) && <Loader />}
|
||||
{/* ========================================================== || Titlecard || ========================================================== */}
|
||||
<TitleCard title="Tenants ">
|
||||
<LocationAutocomplete
|
||||
locations={locations}
|
||||
locaName={locaName}
|
||||
setAppId={setAppId}
|
||||
setLocoName={setLocoName}
|
||||
setPage={setPage}
|
||||
sx={{ width: { xs: '100%', custom450: 300 }, zIndex: '100' }}
|
||||
/>
|
||||
</TitleCard>
|
||||
{/* ========================================================== || MainCard (searchword) || ========================================================== */}
|
||||
<MainCard
|
||||
content={false}
|
||||
sx={{ mt: 2 }}
|
||||
title={
|
||||
{/* ============================================= || Header | ============================================= */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
mb: { xs: 1.5, md: 2 },
|
||||
p: { xs: 1.5, sm: 2, md: 2.5 },
|
||||
borderRadius: DT.radiusCard / 8,
|
||||
border: '1px solid',
|
||||
borderColor: DT.borderSubtle,
|
||||
background: `linear-gradient(135deg, ${tint('#6366f1')} 0%, ${tint('#0ea5e9')} 100%)`,
|
||||
boxShadow: DT.shadowMd
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction={{ xs: 'column', sm: 'row' }}
|
||||
alignItems={{ xs: 'flex-start', sm: 'center' }}
|
||||
justifyContent="space-between"
|
||||
spacing={{ xs: 1.5, sm: 2 }}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" spacing={{ xs: 1.25, sm: 1.75 }}>
|
||||
<Avatar
|
||||
sx={{
|
||||
width: { xs: 40, sm: 48 },
|
||||
height: { xs: 40, sm: 48 },
|
||||
bgcolor: '#6366f1',
|
||||
color: '#fff',
|
||||
boxShadow: '0 6px 18px rgba(99,102,241,0.32)'
|
||||
}}
|
||||
>
|
||||
<MdGroups size={22} />
|
||||
</Avatar>
|
||||
<Stack>
|
||||
<Typography
|
||||
variant="h3"
|
||||
sx={{
|
||||
fontWeight: 800,
|
||||
color: DT.textPrimary,
|
||||
lineHeight: 1.1,
|
||||
fontSize: { xs: '1.25rem', sm: '1.5rem', md: '1.75rem' }
|
||||
}}
|
||||
>
|
||||
Tenants
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center" spacing={0.75} sx={{ mt: 0.5 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: '50%',
|
||||
bgcolor: '#10b981',
|
||||
boxShadow: '0 0 0 4px rgba(16,185,129,0.18)'
|
||||
}}
|
||||
/>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary, fontWeight: 600 }}>
|
||||
Live · {locaName || 'All Zones'}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<LocationAutocomplete
|
||||
locations={locations}
|
||||
locaName={locaName}
|
||||
setAppId={setAppId}
|
||||
setLocoName={setLocoName}
|
||||
setPage={setPage}
|
||||
pill
|
||||
accentColor="#6366f1"
|
||||
icon={<MdMyLocation size={14} />}
|
||||
placeholder="Select Zone"
|
||||
paperComponent={SoftPaper}
|
||||
sx={{ width: { xs: '100%', sm: 280 }, zIndex: 100 }}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* ============================================= || KPI Cards | ============================================= */}
|
||||
<Grid container spacing={{ xs: 1.25, sm: 1.5, md: 2 }} sx={{ mt: '1px' }}>
|
||||
{KPI_META.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const value = summaryData?.[item.countKey] ?? 0;
|
||||
return (
|
||||
<Grid item key={item.key} xs={12} sm={4}>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
p: { xs: 1.25, sm: 1.75, md: 2.25 },
|
||||
borderRadius: DT.radiusCard / 8,
|
||||
border: '1px solid',
|
||||
borderColor: DT.borderSubtle,
|
||||
background: '#fff',
|
||||
transition: 'transform 0.2s, box-shadow 0.2s, border-color 0.2s',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-3px)',
|
||||
boxShadow: DT.shadowMd,
|
||||
borderColor: edge(item.color)
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
const idx = STATUS_TABS.findIndex((t) => t.countKey === item.countKey);
|
||||
if (idx >= 0) handleChange(null, idx);
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 3,
|
||||
background: `linear-gradient(90deg, ${item.color} 0%, ${soft(item.color)} 100%)`
|
||||
}}
|
||||
/>
|
||||
<Stack direction="row" alignItems="flex-start" justifyContent="space-between" spacing={1}>
|
||||
<Stack spacing={0.5} sx={{ minWidth: 0, flex: 1 }}>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: DT.textSecondary,
|
||||
fontWeight: 700,
|
||||
letterSpacing: 0.4,
|
||||
textTransform: 'uppercase',
|
||||
fontSize: { xs: 10, sm: 11 },
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis'
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Typography>
|
||||
{summaryDataIsLoading ? (
|
||||
<Skeleton sx={{ width: 70, height: { xs: 28, md: 36 } }} animation="wave" />
|
||||
) : (
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 800,
|
||||
color: DT.textPrimary,
|
||||
lineHeight: 1.1,
|
||||
fontSize: { xs: '1.5rem', sm: '1.75rem', md: '2rem' }
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
<Avatar
|
||||
sx={{
|
||||
width: { xs: 36, sm: 42, md: 48 },
|
||||
height: { xs: 36, sm: 42, md: 48 },
|
||||
bgcolor: soft(item.color),
|
||||
color: item.color,
|
||||
boxShadow: `inset 0 0 0 1px ${edge(item.color)}`,
|
||||
flexShrink: 0
|
||||
}}
|
||||
>
|
||||
<Icon size={20} />
|
||||
</Avatar>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
|
||||
{/* ============================================= || Status Tabs + Search || ============================================= */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
mt: { xs: 1.5, md: 2 },
|
||||
p: { xs: 1, md: 1.5 },
|
||||
borderTopLeftRadius: DT.radiusCard / 8,
|
||||
borderTopRightRadius: DT.radiusCard / 8,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
border: '1px solid',
|
||||
borderColor: DT.borderSubtle,
|
||||
borderBottom: 0,
|
||||
background: '#fff'
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={1.5}
|
||||
sx={{ flexWrap: 'wrap-reverse' }}
|
||||
>
|
||||
<Stack
|
||||
minWidth={'100%'}
|
||||
flexDirection={{ xs: 'row', sm: 'row' }}
|
||||
direction="row"
|
||||
spacing={0.75}
|
||||
sx={{
|
||||
p: 1.5,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap-reverse',
|
||||
gap: 1
|
||||
flex: 1,
|
||||
overflowX: 'auto',
|
||||
py: 0.5,
|
||||
px: 0.25,
|
||||
'&::-webkit-scrollbar': { height: 6 },
|
||||
'&::-webkit-scrollbar-thumb': { backgroundColor: DT.borderSubtle, borderRadius: 4 }
|
||||
}}
|
||||
>
|
||||
{/* ============================================= || Tabs || ================================================= */}
|
||||
|
||||
<Tabs value={value0} onChange={handleChange} aria-label="basic tabs example">
|
||||
<Tab
|
||||
label="Active"
|
||||
sx={{ ml: -1 }}
|
||||
onClick={() => {
|
||||
setstatus('active');
|
||||
}}
|
||||
icon={
|
||||
<Chip
|
||||
label={summaryDataIsLoading ? <Skeleton variant="text" width={15} height={10} /> : summaryData?.active || 0}
|
||||
color="primary"
|
||||
variant="light"
|
||||
sx={{ minWidth: 32, justifyContent: 'center' }}
|
||||
size="small"
|
||||
/>
|
||||
}
|
||||
iconPosition="end"
|
||||
/>
|
||||
<Tab
|
||||
label="Pending"
|
||||
onClick={() => {
|
||||
setstatus('pending');
|
||||
}}
|
||||
icon={
|
||||
<Chip
|
||||
label={summaryDataIsLoading ? <Skeleton variant="text" width={15} height={10} /> : summaryData?.pending || 0}
|
||||
color="primary"
|
||||
variant="light"
|
||||
sx={{ minWidth: 32, justifyContent: 'center' }}
|
||||
size="small"
|
||||
/>
|
||||
}
|
||||
iconPosition="end"
|
||||
/>
|
||||
<Tab
|
||||
label="Inactive"
|
||||
onClick={() => {
|
||||
setstatus('inactive');
|
||||
}}
|
||||
icon={
|
||||
<Chip
|
||||
label={summaryDataIsLoading ? <Skeleton variant="text" width={15} height={10} /> : summaryData?.inactive || 0}
|
||||
color="primary"
|
||||
variant="light"
|
||||
sx={{ minWidth: 32, justifyContent: 'center' }}
|
||||
size="small"
|
||||
/>
|
||||
}
|
||||
iconPosition="end"
|
||||
/>
|
||||
</Tabs>
|
||||
|
||||
{/* ============================================= || SearchOutlined || ================================================= */}
|
||||
{STATUS_TABS.map((t, idx) => {
|
||||
const meta = STATUS_META[t.status];
|
||||
const Icon = meta.icon;
|
||||
const active = value0 === idx;
|
||||
const count = summaryData?.[t.countKey] ?? 0;
|
||||
return (
|
||||
<Box
|
||||
key={t.status}
|
||||
onClick={() => {
|
||||
setstatus(t.status);
|
||||
handleChange(null, idx);
|
||||
}}
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: { xs: 0.625, md: 0.875 },
|
||||
pl: 0.5,
|
||||
pr: { xs: 1, md: 1.25 },
|
||||
py: 0.5,
|
||||
flexShrink: 0,
|
||||
cursor: 'pointer',
|
||||
borderRadius: 999,
|
||||
border: `1.5px solid ${active ? meta.color : edge(meta.color)}`,
|
||||
bgcolor: active ? meta.color : tint(meta.color),
|
||||
color: active ? '#fff' : meta.color,
|
||||
fontWeight: 700,
|
||||
boxShadow: active ? `0 6px 18px ${ring(meta.color)}` : 'none',
|
||||
transition: 'all 0.18s',
|
||||
'&:hover': {
|
||||
borderColor: meta.color,
|
||||
boxShadow: active ? `0 6px 18px ${ring(meta.color)}` : `0 0 0 3px ${ring(meta.color)}`
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
width: { xs: 22, md: 26 },
|
||||
height: { xs: 22, md: 26 },
|
||||
bgcolor: active ? 'rgba(255,255,255,0.22)' : soft(meta.color),
|
||||
color: active ? '#fff' : meta.color
|
||||
}}
|
||||
>
|
||||
<Icon size={13} />
|
||||
</Avatar>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{ fontWeight: 800, fontSize: { xs: 11.5, md: 13 }, lineHeight: 1 }}
|
||||
>
|
||||
{meta.label}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
minWidth: { xs: 22, md: 26 },
|
||||
height: { xs: 18, md: 22 },
|
||||
px: 0.625,
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 999,
|
||||
fontSize: { xs: 10, md: 11 },
|
||||
fontWeight: 800,
|
||||
bgcolor: active ? 'rgba(255,255,255,0.22)' : '#fff',
|
||||
color: active ? '#fff' : meta.color,
|
||||
border: active ? 'none' : `1px solid ${edge(meta.color)}`
|
||||
}}
|
||||
>
|
||||
{summaryDataIsLoading ? <Skeleton variant="text" width={14} height={10} /> : count}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
|
||||
{/* Search */}
|
||||
<Box sx={{ width: { xs: '100%', sm: 240, lg: 280 }, flex: { xs: '1 1 100%', sm: '0 0 auto' } }}>
|
||||
<DebounceSearchBar
|
||||
value={searchword}
|
||||
onChange={setSearchword}
|
||||
onDebouncedChange={setDebouncedSearch}
|
||||
sx={{ width: { xs: '100%', custom600: 275 }, m: 0 }}
|
||||
sx={{
|
||||
m: 0,
|
||||
width: '100%',
|
||||
borderRadius: 999,
|
||||
bgcolor: tint('#6366f1'),
|
||||
'& fieldset': { borderColor: edge('#6366f1'), borderWidth: 1.5 },
|
||||
'&:hover fieldset': { borderColor: '#6366f1' },
|
||||
'&.Mui-focused fieldset': { borderColor: '#6366f1', borderWidth: 2 },
|
||||
'&.Mui-focused': { boxShadow: `0 0 0 3px ${ring('#6366f1')}` }
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* ============================================= || Table || ============================================= */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomLeftRadius: DT.radiusCard / 8,
|
||||
borderBottomRightRadius: DT.radiusCard / 8,
|
||||
border: '1px solid',
|
||||
borderColor: DT.borderSubtle,
|
||||
overflow: 'hidden',
|
||||
background: '#fff'
|
||||
}}
|
||||
>
|
||||
{/* ============================================= || TableContainer| ============================================= */}
|
||||
<TableContainer sx={{ maxHeight: 'calc(100vh - 300px)' }}>
|
||||
<Table stickyHeader>
|
||||
<TableContainer
|
||||
sx={{
|
||||
maxHeight: { xs: 'calc(100vh - 220px)', md: 'calc(100vh - 190px)' },
|
||||
'&::-webkit-scrollbar': { width: '10px', height: '10px' },
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
backgroundColor: edge('#6366f1'),
|
||||
borderRadius: '8px',
|
||||
'&:hover': { backgroundColor: '#6366f1' }
|
||||
},
|
||||
'&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt }
|
||||
}}
|
||||
>
|
||||
<Table stickyHeader sx={{ minWidth: { xs: 720, md: 960 } }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{ position: 'sticky !important', bgcolor: '#e1bee7!important' }}>S.No</TableCell>
|
||||
<TableCell sx={{ position: 'sticky !important', bgcolor: '#e1bee7!important' }}>Client</TableCell>
|
||||
<TableCell sx={{ position: 'sticky !important', bgcolor: '#e1bee7!important' }}>Contact</TableCell>
|
||||
<TableCell sx={{ position: 'sticky !important', bgcolor: '#e1bee7!important' }}>Address</TableCell>
|
||||
<TableCell sx={{ position: 'sticky !important', bgcolor: '#e1bee7!important' }} align="center">
|
||||
Actions
|
||||
</TableCell>
|
||||
<TableRow
|
||||
sx={{
|
||||
'& th': {
|
||||
backgroundColor: DT.surfaceAlt,
|
||||
color: DT.textSecondary,
|
||||
fontSize: { xs: 10, md: 11 },
|
||||
fontWeight: 800,
|
||||
letterSpacing: 0.6,
|
||||
textTransform: 'uppercase',
|
||||
whiteSpace: 'nowrap',
|
||||
borderBottom: `1px solid ${DT.borderSubtle}`,
|
||||
py: { xs: 1, md: 1.25 },
|
||||
px: { xs: 1, md: 2 }
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TableCell>#</TableCell>
|
||||
<TableCell>Status</TableCell>
|
||||
<TableCell>Client</TableCell>
|
||||
<TableCell>Contact</TableCell>
|
||||
<TableCell>Address</TableCell>
|
||||
<TableCell align="right">Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
@@ -589,111 +927,220 @@ const Clients1 = () => {
|
||||
|
||||
{tenantList?.length == 0 && !isloader ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6}>
|
||||
<Stack width={'100%'} direction={'row'} justifyContent={'center'}>
|
||||
<Empty description={`No ${tabStatus} Tenants`} styles={{ description: { color: theme.palette.error.main } }} />
|
||||
<TableCell colSpan={6} sx={{ py: 6 }}>
|
||||
<Stack alignItems="center" spacing={1.5}>
|
||||
<Avatar sx={{ width: 64, height: 64, bgcolor: soft('#94a3b8'), color: DT.textMuted }}>
|
||||
<MdGroups size={28} />
|
||||
</Avatar>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700, color: DT.textPrimary }}>
|
||||
No tenants to show
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
|
||||
{`No ${activeTabMeta.label.toLowerCase()} tenants for this filter.`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
tenantList?.map((row, index) => (
|
||||
<>
|
||||
tenantList?.map((row, index) => {
|
||||
const rowStatusKey = (value0 === 0 ? 'active' : value0 === 1 ? 'pending' : 'inactive');
|
||||
const rowStatusMeta = STATUS_META[rowStatusKey];
|
||||
const RowStatusIcon = rowStatusMeta.icon;
|
||||
return (
|
||||
<Fragment key={row.tenantid ?? index}>
|
||||
{/* ============================================ || tablerow 1 || ============================================ */}
|
||||
<TableRow key={index}>
|
||||
<TableCell>{index + 1 + page * rowsPerPage}</TableCell>
|
||||
<TableRow
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
transition: 'background-color 0.15s',
|
||||
'& td': {
|
||||
borderBottom: `1px solid ${DT.divider}`,
|
||||
py: { xs: 1, md: 1.5 },
|
||||
px: { xs: 1, md: 2 }
|
||||
},
|
||||
'&:hover': { backgroundColor: DT.surfaceAlt }
|
||||
}}
|
||||
>
|
||||
<TableCell>
|
||||
<Stack>
|
||||
<Typography variant="subtitle1" sx={{ whiteSpace: 'nowrap' }}>
|
||||
{row.tenantname}
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textMuted }}>
|
||||
{String(index + 1 + page * rowsPerPage).padStart(2, '0')}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={0.5}
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
pl: 0.5,
|
||||
pr: 1,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
bgcolor: tint(rowStatusMeta.color),
|
||||
border: `1px solid ${edge(rowStatusMeta.color)}`,
|
||||
color: rowStatusMeta.color
|
||||
}}
|
||||
>
|
||||
<AccentAvatar color={rowStatusMeta.color} size={20}>
|
||||
<RowStatusIcon size={12} />
|
||||
</AccentAvatar>
|
||||
<Typography variant="caption" sx={{ fontWeight: 800, fontSize: 11, lineHeight: 1 }}>
|
||||
{rowStatusMeta.label}
|
||||
</Typography>
|
||||
<Typography variant="body2">Id : {row.tenantid}</Typography>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>{row.primarycontact}</Typography>
|
||||
<Typography color="secondary">{row.primaryemail}</Typography>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<AccentAvatar color="#6366f1" size={32}>
|
||||
<MdPersonPin size={16} />
|
||||
</AccentAvatar>
|
||||
<Stack>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}>
|
||||
{row.tenantname}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
|
||||
ID #{row.tenantid}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell sx={{ whiteSpace: 'wrap' }}>{row.address}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Stack direction={'row'}>
|
||||
<IconButton
|
||||
<TableCell>
|
||||
<Stack>
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}>
|
||||
{row.primarycontact || '—'}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
|
||||
{row.primaryemail || '—'}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell sx={{ maxWidth: 280 }}>
|
||||
<Tooltip title={row.address || ''} placement="top">
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: value0 == 1 ? theme.palette.primary.main : theme.palette.success.main
|
||||
color: DT.textSecondary,
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 2,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Tooltip title={value0 == 0 ? 'Inactive' : value == 1 ? 'Approve' : 'Active'} placement="top">
|
||||
{value0 == 0 ? (
|
||||
<StopOutlined
|
||||
style={{ color: 'red' }}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
setClientstatus(row.approved);
|
||||
setTimeout(() => {
|
||||
tenantupdate(row.tenantid);
|
||||
}, 100);
|
||||
}}
|
||||
/>
|
||||
) : value0 == 1 ? (
|
||||
<IssuesCloseOutlined
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setDialogopen(true);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
getAppPricing(row.applolcationid);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FaRegCheckCircle
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
setTimeout(() => {
|
||||
tenantupdate(row.tenantid);
|
||||
}, 100);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{row.address || '—'}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Stack direction="row" spacing={0.75} justifyContent="flex-end">
|
||||
{value0 == 0 && (
|
||||
<Tooltip title="Inactivate" placement="top">
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: soft('#ef4444'),
|
||||
color: '#ef4444',
|
||||
border: `1px solid ${edge('#ef4444')}`,
|
||||
'&:hover': { bgcolor: '#ef4444', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
setTimeout(() => {
|
||||
tenantupdate(row.tenantid);
|
||||
}, 100);
|
||||
}}
|
||||
>
|
||||
<StopOutlined style={{ fontSize: 14 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="medium"
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
handleCollapseToggle1(index); // makes 1st collpase open
|
||||
setOpenRowIndex2(-1); //makes 2nd collapse close , if open
|
||||
setSelectedtenid(row.tenantid);
|
||||
// setAppId(row.applocationid);
|
||||
}}
|
||||
sx={{
|
||||
color: openRowIndex1 === index ? theme.palette.error.main : theme.palette.primary.main
|
||||
}}
|
||||
>
|
||||
{openRowIndex1 === index ? <EyeInvisibleOutlined /> : <EyeOutlined />}
|
||||
</IconButton>
|
||||
{value0 !== 1 && (
|
||||
)}
|
||||
{value0 == 1 && (
|
||||
<Tooltip title="Approve" placement="top">
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: soft('#f59e0b'),
|
||||
color: '#f59e0b',
|
||||
border: `1px solid ${edge('#f59e0b')}`,
|
||||
'&:hover': { bgcolor: '#f59e0b', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setDialogopen(true);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
getAppPricing(row.applolcationid);
|
||||
}}
|
||||
>
|
||||
<IssuesCloseOutlined style={{ fontSize: 14 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{value0 == 2 && (
|
||||
<Tooltip title="Activate" placement="top">
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: soft('#10b981'),
|
||||
color: '#10b981',
|
||||
border: `1px solid ${edge('#10b981')}`,
|
||||
'&:hover': { bgcolor: '#10b981', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
setTimeout(() => {
|
||||
tenantupdate(row.tenantid);
|
||||
}, 100);
|
||||
}}
|
||||
>
|
||||
<FaRegCheckCircle style={{ fontSize: 14 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={openRowIndex1 === index ? 'Hide details' : 'View details'} placement="top">
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="medium"
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: openRowIndex1 === index ? '#6366f1' : soft('#6366f1'),
|
||||
color: openRowIndex1 === index ? '#fff' : '#6366f1',
|
||||
border: `1px solid ${edge('#6366f1')}`,
|
||||
'&:hover': { bgcolor: '#6366f1', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
handleCollapseToggle2(index); // makse 2nd collpase open
|
||||
setOpenRowIndex1(-1); // makse 1st collpse close if open
|
||||
handleCollapseToggle1(index);
|
||||
setOpenRowIndex2(-1);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
}}
|
||||
sx={{
|
||||
color: openRowIndex2 === index ? theme.palette.error.main : theme.palette.primary.main
|
||||
}}
|
||||
>
|
||||
<Tooltip title={openRowIndex2 === index ? 'Close' : 'Edit'} placement="top">
|
||||
{openRowIndex2 === index ? <CloseOutlined /> : <EditOutlined />}
|
||||
</Tooltip>
|
||||
{openRowIndex1 === index ? <EyeInvisibleOutlined style={{ fontSize: 14 }} /> : <EyeOutlined style={{ fontSize: 14 }} />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{value0 !== 1 && (
|
||||
<Tooltip title={openRowIndex2 === index ? 'Close' : 'Edit'} placement="top">
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: openRowIndex2 === index ? '#8b5cf6' : soft('#8b5cf6'),
|
||||
color: openRowIndex2 === index ? '#fff' : '#8b5cf6',
|
||||
border: `1px solid ${edge('#8b5cf6')}`,
|
||||
'&:hover': { bgcolor: '#8b5cf6', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedCustomer(row);
|
||||
handleCollapseToggle2(index);
|
||||
setOpenRowIndex1(-1);
|
||||
setSelectedtenid(row.tenantid);
|
||||
setAppId(row.applocationid);
|
||||
}}
|
||||
>
|
||||
{openRowIndex2 === index ? <CloseOutlined style={{ fontSize: 14 }} /> : <EditOutlined style={{ fontSize: 14 }} />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Stack>
|
||||
</TableCell>
|
||||
@@ -1532,21 +1979,20 @@ const Clients1 = () => {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</>
|
||||
))
|
||||
</Fragment>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Divider />
|
||||
{/* ============================================= || Pagination| ============================================= */}
|
||||
{!searchword && tenantList?.length > 0 && (
|
||||
<>
|
||||
<Divider />
|
||||
<Divider sx={{ borderColor: DT.borderSubtle }} />
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, 50, 100]}
|
||||
component="div"
|
||||
// count={pageno}
|
||||
count={value0 == 0 ? summaryData?.active : value0 == 1 ? summaryData?.pending : value0 == 2 ? summaryData?.inactive : 0}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
@@ -1555,7 +2001,7 @@ const Clients1 = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</MainCard>
|
||||
</Paper>
|
||||
{/* // ==============================||( Client Pricing ) dialog (dialogopen) ||============================== // */}
|
||||
<Dialog fullWidth={true} open={dialogopen} onClose={dialogclose} scroll={'paper'} maxWidth="sm" TransitionComponent={PopupTransition}>
|
||||
<DialogTitle
|
||||
@@ -1710,7 +2156,7 @@ const Clients1 = () => {
|
||||
</Grid>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user