Removed duplicate filter in settings page

Improved Rule value handling
This commit is contained in:
2026-09-28 11:10:17 +02:00
parent ef13117042
commit 93b3416d2c
2 changed files with 9 additions and 107 deletions
@@ -582,14 +582,15 @@ export const USER_ROLE_OPTIONS = [
{ value: 'Supervisor', label: 'Supervisor' },
{ value: 'Manager', label: 'Manager' },
{ value: 'Contributor', label: 'Contributor' },
{ value: 'Unassigned', label: 'Unassigned' },
];
export const getUserRoleBadge = (role?: string | number | UserRole | null) => {
if (role === null || role === undefined || role === '') {
if (role === null || role === undefined || role === '' || String(role).trim().toLowerCase() === 'null' || String(role).trim().toLowerCase() === 'unassigned') {
return {
label: 'Contributor',
className: 'bg-emerald-500/15 text-emerald-300 border-emerald-500/30',
dot: 'bg-emerald-400',
label: 'Unassigned',
className: 'bg-slate-800/80 text-slate-400 border-slate-700/80 shadow-xs',
dot: 'bg-slate-500',
};
}
@@ -47,8 +47,6 @@ import {
getUserSyncRecord,
getInvites,
sendInvite,
getApplicantInvite,
getApplicantInvites,
getOrganisations,
getAwards,
getContracts,
@@ -131,10 +129,11 @@ export const SettingsPage: React.FC = () => {
const filteredUsers = useMemo(() => {
return usersList.filter((u) => {
const roleLabel = getUserRoleBadge(u.role).label;
const matchRole =
userRoleFilter === 'all' ||
(u.role && String(u.role).toLowerCase() === userRoleFilter.toLowerCase()) ||
(!u.role && userRoleFilter.toLowerCase() === 'contributor');
roleLabel.toLowerCase() === userRoleFilter.toLowerCase() ||
(u.role && String(u.role).toLowerCase() === userRoleFilter.toLowerCase());
return matchRole;
});
}, [usersList, userRoleFilter]);
@@ -198,9 +197,6 @@ export const SettingsPage: React.FC = () => {
// 2. Communications & Invites State
// ==========================================
const [isSendInviteModalOpen, setIsSendInviteModalOpen] = useState(false);
const [applicantSearchId, setApplicantSearchId] = useState('');
const [applicantInvitesResults, setApplicantInvitesResults] = useState<Invite[] | null>(null);
const [searchingApplicant, setSearchingApplicant] = useState(false);
// Invite Form State
const [inviteOrgId, setInviteOrgId] = useState<string | number>('');
@@ -266,37 +262,6 @@ export const SettingsPage: React.FC = () => {
},
});
const handleSearchApplicantInvites = async (e?: React.FormEvent) => {
if (e) e.preventDefault();
if (!applicantSearchId.trim()) return;
try {
setSearchingApplicant(true);
const res = await getApplicantInvites(applicantSearchId.trim());
setApplicantInvitesResults(res);
success('Lookup Complete', `Retrieved ${res.length} invitation records for applicant.`);
} catch (err: any) {
toastError('Lookup Error', err);
setApplicantInvitesResults([]);
} finally {
setSearchingApplicant(false);
}
};
const handleLookupSingleApplicantInvite = async () => {
if (!applicantSearchId.trim()) return;
try {
setSearchingApplicant(true);
const res = await getApplicantInvite(applicantSearchId.trim());
setApplicantInvitesResults(res ? [res] : []);
success('Primary Invite Found', `Retrieved primary invitation for applicant.`);
} catch (err: any) {
toastError('Lookup Error', err);
setApplicantInvitesResults([]);
} finally {
setSearchingApplicant(false);
}
};
// ==========================================
// 3. Email Gateway & Notifications State
// ==========================================
@@ -908,71 +873,7 @@ export const SettingsPage: React.FC = () => {
{/* TAB 2: Communications & Invites */}
{/* ============================================================== */}
{activeTab === 'invites' && (
<div className="space-y-6">
{/* Applicant Invites Lookup */}
<div className="bg-[#0f1523]/80 backdrop-blur-md p-5 rounded-2xl border border-slate-800/80 shadow-xl">
<h3 className="text-sm font-bold text-white mb-1">Applicant Invitations Lookup</h3>
<p className="text-xs text-slate-400 mb-3">
Query invitations dispatched to a specific candidate or grantee using their unique Applicant User UUID.
</p>
<form onSubmit={handleSearchApplicantInvites} className="flex gap-2">
<input
type="text"
value={applicantSearchId}
onChange={(e) => setApplicantSearchId(e.target.value)}
placeholder="Enter Applicant User ID (UUID)..."
className="flex-1 px-3 py-2 text-xs bg-slate-900/80 border border-slate-700/80 rounded-xl text-white placeholder-slate-500 font-mono focus:outline-none focus:ring-2 focus:ring-blue-500/50"
/>
<button
type="submit"
disabled={searchingApplicant || !applicantSearchId.trim()}
className="px-3.5 py-2 text-xs font-semibold text-white bg-blue-600 hover:bg-blue-500 rounded-xl transition cursor-pointer disabled:opacity-50"
title="Lookup all invites"
>
{searchingApplicant ? 'Searching...' : 'All Invites'}
</button>
<button
type="button"
onClick={handleLookupSingleApplicantInvite}
disabled={searchingApplicant || !applicantSearchId.trim()}
className="px-3.5 py-2 text-xs font-semibold text-blue-300 bg-blue-500/10 hover:bg-blue-500/20 border border-blue-500/30 rounded-xl transition cursor-pointer disabled:opacity-50"
title="Lookup primary invite"
>
Primary Invite
</button>
</form>
{applicantInvitesResults && (
<div className="mt-4 pt-4 border-t border-slate-800/80">
<span className="text-xs font-semibold text-slate-300">
Lookup Results ({applicantInvitesResults.length} matches):
</span>
{applicantInvitesResults.length === 0 ? (
<p className="text-xs text-slate-500 mt-2">No invitations found for this applicant UUID.</p>
) : (
<div className="mt-2 space-y-2">
{applicantInvitesResults.map((inv, idx) => (
<div
key={idx}
className="p-3 bg-slate-900/60 rounded-xl border border-slate-800 text-xs flex flex-col sm:flex-row sm:items-center justify-between gap-2"
>
<div>
<span className="font-semibold text-white">{inv.message}</span>
<div className="text-[11px] text-slate-400 mt-0.5">
Org #{inv.organisationId} &bull; Award #{inv.awardId} &bull; Contract #{inv.contractId}
</div>
</div>
<span className="text-[10px] font-mono px-2 py-0.5 rounded bg-blue-500/10 text-blue-400 border border-blue-500/20">
{getNotificationPlatformLabel(inv.platform)}
</span>
</div>
))}
</div>
)}
</div>
)}
</div>
<div className="space-y-4">
{/* Standardized Toolbar & Filter Bar directly above Sent Invitations Table */}
<div className="bg-[#0f1523]/80 backdrop-blur-md p-3.5 sm:p-4 rounded-2xl border border-slate-800/80 shadow-xl flex flex-col lg:flex-row items-stretch lg:items-center justify-between gap-3">
{/* Filters on the left */}