Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions client/src/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ const Sidebar = () => {
username?: string;
status?: string;
lastOnline?: string;
isOnline?: boolean;
online?: boolean;
data?: any;
}

Expand Down Expand Up @@ -529,7 +529,7 @@ const Sidebar = () => {
<div className="flex flex-col items-start">
<span className="font-medium">{player.username || 'Unknown'}</span>
<span className="text-muted-foreground text-[10px]">
{player.status}
{player.online ? 'Online' : 'Offline'}
</span>
</div>
</Button>
Expand Down Expand Up @@ -571,7 +571,7 @@ const Sidebar = () => {
<div className="flex flex-col items-start">
<span className="font-medium">{player.username || 'Unknown'}</span>
<span className="text-muted-foreground text-[10px]">
{player.status || 'Offline'}
{player.online ? 'Online' : 'Offline'}
</span>
</div>
</Button>
Expand Down
70 changes: 38 additions & 32 deletions client/src/components/windows/PlayerWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ interface PlayerInfo {
playtime: string;
social: string;
gameplay: string;
punished: boolean;
punishmentStatus: 'banned' | 'muted' | null;
previousNames: string[];
warnings: Array<{
type: string;
Expand Down Expand Up @@ -619,7 +619,7 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
playtime: '342 hours',
social: 'Low',
gameplay: 'Medium',
punished: false,
punishmentStatus: null,
previousNames: ['Dragon55', 'SlayerXD'],
warnings: [
{ type: 'Warning', reason: 'Excessive caps in chat', date: '2023-04-12', by: 'Moderator2' },
Expand Down Expand Up @@ -850,16 +850,20 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
.map((u: any) => u.username)
: [];

// Determine player status (exclude kicks from status calculation)
// Kicks (ordinal 0) should never affect the "Currently Punished" badge
const activePunishments = player.punishments ? player.punishments.filter((p: any) =>
// Determine player status using effectiveCategory from backend
const activePunishments = player.punishments ? player.punishments.filter((p: any) =>
p.active && p.typeOrdinal !== 0 // Exclude kicks (ordinal 0) completely
) : [];

const status = activePunishments.some((p: any) => !p.expires)
? 'Banned'

const hasActiveBan = activePunishments.some((p: any) => p.effectiveCategory === 'BAN');
const hasActiveMute = activePunishments.some((p: any) => p.effectiveCategory === 'MUTE');

const status = hasActiveBan
? 'Banned'
: hasActiveMute
? 'Muted'
: activePunishments.length > 0
? 'Restricted'
? 'Restricted'
: 'Active';

// Initialize warnings array - do NOT include staff notes as warnings
Expand Down Expand Up @@ -946,7 +950,8 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
return data;
})(),
altBlocking: punishment.data?.altBlocking || (punishment.data?.get ? punishment.data.get('altBlocking') : false),
started: punishment.started
started: punishment.started,
effectiveCategory: punishment.effectiveCategory
});
});
}
Expand Down Expand Up @@ -1017,7 +1022,7 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
})(),
social: calculatedStatus.social,
gameplay: calculatedStatus.gameplay,
punished: status !== 'Active',
punishmentStatus: hasActiveBan ? 'banned' : hasActiveMute ? 'muted' : null,
previousNames: previousNames,
warnings: warnings,
linkedAccounts: linkedAccounts,
Expand Down Expand Up @@ -1149,18 +1154,26 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind

// Helper function to get original punishment action (ban/mute/kick) for display
const getOriginalPunishmentAction = (warning: any, punishmentType: any) => {
// Check for explicit action types first
// Use the backend-computed effective category when available (authoritative source)
const effectiveCategory = warning.effectiveCategory || warning.data?.effectiveCategory;
if (effectiveCategory) {
const originalDuration = warning.duration || warning.data?.duration;
const isPermanent = originalDuration === 0 || originalDuration === -1 || (originalDuration != null && originalDuration < 0);
if (effectiveCategory === 'BAN') return isPermanent ? 'permanent ban' : 'ban';
if (effectiveCategory === 'MUTE') return isPermanent ? 'permanent mute' : 'mute';
}

// Check for explicit action types in the name (administrative types like Manual Mute, Manual Ban)
if (warning.type?.toLowerCase().includes('kick')) return 'kick';
if (warning.type?.toLowerCase().includes('mute')) return 'mute';
if (warning.type?.toLowerCase().includes('ban') || warning.type?.toLowerCase().includes('blacklist')) return 'ban';

// If we have punishment type configuration, look up the actual action based on duration data
if (punishmentType && warning) {
// Get the severity and status from the punishment data
const severity = warning.severity || warning.data?.severity;
const status = warning.status || warning.data?.status;
const originalDuration = warning.duration || warning.data?.duration;


// For single severity punishments, check singleSeverityDurations
if (punishmentType.singleSeverityPunishment && punishmentType.singleSeverityDurations) {
const offenseLevel = status === 'low' ? 'first' : status === 'medium' ? 'medium' : 'habitual';
Expand All @@ -1169,7 +1182,7 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
return durationConfig.type; // This will be 'mute', 'ban', 'permanent mute', or 'permanent ban'
}
}

// For multi-severity punishments, check durations
if (punishmentType.durations && severity) {
const severityKey = severity === 'lenient' ? 'low' : severity === 'regular' ? 'regular' : 'severe';
Expand All @@ -1179,24 +1192,13 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
return durationConfig.type; // This will be 'mute', 'ban', 'permanent mute', or 'permanent ban'
}
}

// If we can't determine from configuration, check if it's permanent based on duration
if (originalDuration === 0 || originalDuration === -1 || originalDuration < 0) {
// Default to permanent ban for permanent punishments if we can't determine otherwise
return 'permanent ban';
}
}

// Check if the punishment type has an action property
if (punishmentType?.action) {
return punishmentType.action;
}

// For other punishment types with durations, default to ban
if (punishmentType?.durations || punishmentType?.singleSeverityDurations) {
return 'ban';
}


return 'punishment';
};

Expand Down Expand Up @@ -1475,9 +1477,13 @@ const PlayerWindow = ({ playerId, isOpen, onClose, initialPosition }: PlayerWind
}>
Gameplay: {playerInfo.gameplay.toLowerCase()}
</Badge>
{playerInfo.punished && (
<Badge variant="outline" className="bg-destructive/10 text-destructive border-destructive/20">
Currently Punished
{playerInfo.punishmentStatus && (
<Badge variant="outline" className={
playerInfo.punishmentStatus === 'banned'
? "bg-destructive/10 text-destructive border-destructive/20"
: "bg-warning/10 text-warning border-warning/20"
}>
{playerInfo.punishmentStatus === 'banned' ? 'Currently banned' : 'Currently muted'}
</Badge>
)}
</div>
Expand Down
22 changes: 13 additions & 9 deletions client/src/pages/lookup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,15 @@ const PlayerLookupWindow = ({
? ipAddresses[ipAddresses.length - 1].ipAddress.replace(/\d+$/, 'x.x')
: 'Unknown';

// Determine player status
const status = player.punishments && player.punishments.some((p: any) => p.active && !p.expires)
? 'Banned'
: player.punishments && player.punishments.some((p: any) => p.active)
? 'Restricted'
// Determine player status using effectiveCategory from backend
const hasActiveBan = player.punishments && player.punishments.some((p: any) => p.active && p.effectiveCategory === 'BAN');
const hasActiveMute = player.punishments && player.punishments.some((p: any) => p.active && p.effectiveCategory === 'MUTE');
const status = hasActiveBan
? 'Banned'
: hasActiveMute
? 'Muted'
: player.punishments && player.punishments.some((p: any) => p.active)
? 'Restricted'
: 'Active';

// Format warnings from notes
Expand Down Expand Up @@ -209,11 +213,11 @@ const PlayerLookupWindow = ({
<div className="flex-1 min-w-0">
<h5 className="text-lg font-medium">{playerInfo.username || 'Unknown'}</h5>
<div className="flex flex-wrap gap-2 mt-1">
<Badge
variant="outline"
<Badge
variant="outline"
className={`
${playerInfo.status === 'Online' ? 'bg-success/10 text-success border-success/20' :
playerInfo.status === 'Restricted' ? 'bg-warning/10 text-warning border-warning/20' :
${playerInfo.status === 'Online' || playerInfo.status === 'Active' ? 'bg-success/10 text-success border-success/20' :
playerInfo.status === 'Muted' || playerInfo.status === 'Restricted' ? 'bg-warning/10 text-warning border-warning/20' :
'bg-destructive/10 text-destructive border-destructive/20'
}
`}
Expand Down
34 changes: 21 additions & 13 deletions client/src/pages/player-detail-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ interface PlayerInfo {
playtime: string;
social: string;
gameplay: string;
punished: boolean;
punishmentStatus: 'banned' | 'muted' | null;
previousNames: string[];
warnings: Array<{
type: string;
Expand Down Expand Up @@ -236,7 +236,7 @@ const PlayerDetailPage = () => {
playtime: 'Unknown',
social: 'Medium',
gameplay: 'Medium',
punished: false,
punishmentStatus: null,
previousNames: [],
warnings: [],
linkedAccounts: [],
Expand Down Expand Up @@ -530,16 +530,20 @@ const PlayerDetailPage = () => {
.map((u: any) => u.username)
: [];

// Determine player status (exclude kicks from status calculation)
// Kicks (ordinal 0) should never affect the "Currently Punished" badge
const activePunishments = player.punishments ? player.punishments.filter((p: any) =>
// Determine player status using effectiveCategory from backend
const activePunishments = player.punishments ? player.punishments.filter((p: any) =>
p.active && p.typeOrdinal !== 0 // Exclude kicks (ordinal 0) completely
) : [];

const status = activePunishments.some((p: any) => !p.expires)
? 'Banned'

const hasActiveBan = activePunishments.some((p: any) => p.effectiveCategory === 'BAN');
const hasActiveMute = activePunishments.some((p: any) => p.effectiveCategory === 'MUTE');

const status = hasActiveBan
? 'Banned'
: hasActiveMute
? 'Muted'
: activePunishments.length > 0
? 'Restricted'
? 'Restricted'
: 'Active';

// Initialize warnings array
Expand Down Expand Up @@ -683,7 +687,7 @@ const PlayerDetailPage = () => {
})(),
social: calculatedStatus.social,
gameplay: calculatedStatus.gameplay,
punished: status !== 'Active',
punishmentStatus: hasActiveBan ? 'banned' : hasActiveMute ? 'muted' : null,
previousNames: previousNames,
warnings: warnings,
linkedAccounts: linkedAccounts,
Expand Down Expand Up @@ -1138,9 +1142,13 @@ const PlayerDetailPage = () => {
}>
Gameplay: {playerInfo.gameplay.toLowerCase()}
</Badge>
{playerInfo.punished && (
<Badge variant="outline" className="bg-destructive/10 text-destructive border-destructive/20">
Currently Punished
{playerInfo.punishmentStatus && (
<Badge variant="outline" className={
playerInfo.punishmentStatus === 'banned'
? "bg-destructive/10 text-destructive border-destructive/20"
: "bg-warning/10 text-warning border-warning/20"
}>
{playerInfo.punishmentStatus === 'banned' ? 'Currently banned' : 'Currently muted'}
</Badge>
)}
</div>
Expand Down