refactor: additional design feedback improvements

This commit is contained in:
Gustav
2025-01-31 11:50:43 -07:00
parent afdaeb3d34
commit dff8fc6396
11 changed files with 376 additions and 201 deletions

View File

@@ -0,0 +1,52 @@
import React from 'react';
import clsx from 'clsx';
import { zkillLink } from '../helpers';
import classes from './SystemKillRow.module.scss';
interface AttackerRowSubInfoProps {
finalBlowCharId: number | null | undefined;
finalBlowCharName?: string;
attackerPortraitUrl: string | null;
finalBlowCorpId: number | null | undefined;
finalBlowCorpName?: string;
attackerCorpLogoUrl: string | null;
finalBlowAllianceId: number | null | undefined;
finalBlowAllianceName?: string;
attackerAllianceLogoUrl: string | null;
containerHeight?: number;
}
export const AttackerRowSubInfo: React.FC<AttackerRowSubInfoProps> = ({
finalBlowCharId = 0,
finalBlowCharName,
attackerPortraitUrl,
containerHeight = 8,
}) => {
if (!attackerPortraitUrl || finalBlowCharId === null || finalBlowCharId <= 0) {
return null;
}
const containerClass = `h-${containerHeight}`;
return (
<div className={clsx('flex items-start gap-1', containerClass)}>
<div className="relative shrink-0 w-auto h-full overflow-hidden">
<a
href={zkillLink('character', finalBlowCharId)}
target="_blank"
rel="noopener noreferrer"
className="block h-full"
>
<img
src={attackerPortraitUrl}
alt={finalBlowCharName || 'AttackerPortrait'}
className={clsx(classes.killRowImage, 'h-full w-auto object-contain')}
/>
</a>
</div>
</div>
);
};

View File

@@ -7,9 +7,13 @@ import {
zkillLink, zkillLink,
getAttackerSubscript, getAttackerSubscript,
buildVictimImageUrls, buildVictimImageUrls,
buildAttackerShipUrl, buildAttackerImageUrls,
getPrimaryLogoAndTooltip,
getAttackerPrimaryImageAndTooltip,
} from '../helpers'; } from '../helpers';
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
import classes from './SystemKillRow.module.scss'; import classes from './SystemKillRow.module.scss';
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
export interface CompactKillRowProps { export interface CompactKillRowProps {
killDetails: DetailedKill; killDetails: DetailedKill;
@@ -19,44 +23,69 @@ export interface CompactKillRowProps {
export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => { export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
const { const {
killmail_id, killmail_id = 0,
victim_char_name = 'Unknown Pilot', victim_char_name = 'Unknown Pilot',
victim_alliance_ticker = '',
victim_corp_ticker = '',
victim_ship_name = 'Unknown Ship', victim_ship_name = 'Unknown Ship',
victim_alliance_ticker, victim_corp_name = '',
victim_corp_ticker, victim_alliance_name = '',
victim_char_id, victim_char_id = 0,
victim_corp_id, victim_corp_id = 0,
victim_alliance_id, victim_alliance_id = 0,
victim_ship_type_id, victim_ship_type_id = 0,
final_blow_char_id, final_blow_char_id = 0,
final_blow_char_name = '', final_blow_char_name = '',
final_blow_alliance_ticker, final_blow_alliance_ticker = '',
final_blow_corp_ticker, final_blow_alliance_name = '',
final_blow_ship_type_id, final_blow_alliance_id = 0,
final_blow_corp_ticker = '',
final_blow_corp_id = 0,
final_blow_corp_name = '',
final_blow_ship_type_id = 0,
kill_time, kill_time = '',
total_value, total_value = 0,
} = killDetails; } = killDetails || {};
const attackerIsNpc = final_blow_char_id == null;
const attackerIsNpc = final_blow_char_id === 0;
const victimAffiliationTicker = victim_alliance_ticker || victim_corp_ticker || 'No Ticker'; const victimAffiliationTicker = victim_alliance_ticker || victim_corp_ticker || 'No Ticker';
const killValueFormatted = total_value && total_value > 0 ? `${formatISK(total_value)} ISK` : null; const killValueFormatted = total_value != null && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
const attackerName = attackerIsNpc ? '' : final_blow_char_name; const attackerName = attackerIsNpc ? '' : final_blow_char_name;
const attackerTicker = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || ''; const attackerTicker = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago'; const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
const attackerSubscript = getAttackerSubscript(killDetails); const attackerSubscript = getAttackerSubscript(killDetails);
const { victimShipUrl } = buildVictimImageUrls({ const { victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
victim_char_id, victim_char_id,
victim_ship_type_id, victim_ship_type_id,
victim_corp_id, victim_corp_id,
victim_alliance_id, victim_alliance_id,
}); });
const finalBlowShipUrl = buildAttackerShipUrl(final_blow_ship_type_id); const { attackerCorpLogoUrl, attackerAllianceLogoUrl } = buildAttackerImageUrls({
final_blow_char_id,
final_blow_corp_id,
final_blow_alliance_id,
});
const { url: victimPrimaryLogoUrl, tooltip: victimPrimaryTooltip } = getPrimaryLogoAndTooltip(
victimAllianceLogoUrl,
victimCorpLogoUrl,
victim_alliance_name,
victim_corp_name,
'Victim',
);
const { url: attackerPrimaryImageUrl, tooltip: attackerPrimaryTooltip } = getAttackerPrimaryImageAndTooltip(
attackerIsNpc,
attackerAllianceLogoUrl,
attackerCorpLogoUrl,
final_blow_alliance_name,
final_blow_corp_name,
final_blow_ship_type_id || 0,
);
return ( return (
<div <div
@@ -65,15 +94,21 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
'text-xs whitespace-nowrap overflow-hidden leading-none', 'text-xs whitespace-nowrap overflow-hidden leading-none',
)} )}
> >
{victimShipUrl && ( {victimPrimaryLogoUrl && (
<a <WdTooltipWrapper content={victimPrimaryTooltip} position={TooltipPosition.top}>
href={zkillLink('kill', killmail_id)} <a
target="_blank" href={zkillLink('kill', killmail_id)}
rel="noopener noreferrer" target="_blank"
className="relative shrink-0 w-8 h-8 overflow-hidden" rel="noopener noreferrer"
> className="relative shrink-0 w-8 h-8 overflow-hidden"
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} /> >
</a> <img
src={victimPrimaryLogoUrl}
alt="VictimPrimaryLogo"
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
/>
</a>
</WdTooltipWrapper>
)} )}
<div className="flex flex-col ml-2 min-w-0 overflow-hidden leading-[1rem]"> <div className="flex flex-col ml-2 min-w-0 overflow-hidden leading-[1rem]">
@@ -103,7 +138,7 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
<div className="truncate text-stone-400"> <div className="truncate text-stone-400">
{!onlyOneSystem && systemName ? ( {!onlyOneSystem && systemName ? (
<> <>
{systemName} /<span className="ml-1 text-red-400">{killTimeAgo}</span> {systemName} / <span className="ml-1 text-red-400">{killTimeAgo}</span>
</> </>
) : ( ) : (
<span className="text-red-400">{killTimeAgo}</span> <span className="text-red-400">{killTimeAgo}</span>
@@ -111,27 +146,33 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
</div> </div>
</div> </div>
{finalBlowShipUrl && ( {attackerPrimaryImageUrl && (
<a <WdTooltipWrapper content={attackerPrimaryTooltip} position={TooltipPosition.top}>
href={zkillLink('kill', killmail_id)} <a
target="_blank" href={zkillLink('kill', killmail_id)}
rel="noopener noreferrer" target="_blank"
className="relative shrink-0 w-8 h-8 overflow-hidden" rel="noopener noreferrer"
> className="relative shrink-0 w-8 h-8 overflow-hidden"
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} /> >
{attackerSubscript && ( <img
<span src={attackerPrimaryImageUrl}
className={clsx( alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
classes.attackerCountLabel, className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
attackerSubscript.cssClass, />
'text-[0.6rem] leading-none px-[2px]', {attackerSubscript && (
)} <span
style={{ bottom: 0, right: 0 }} className={clsx(
> classes.attackerCountLabel,
{attackerSubscript.label} attackerSubscript.cssClass,
</span> 'text-[0.6rem] leading-none px-[2px]',
)} )}
</a> style={{ bottom: 0, right: 0 }}
>
{attackerSubscript.label}
</span>
)}
</a>
</WdTooltipWrapper>
)} )}
</div> </div>
</div> </div>

View File

@@ -1,16 +1,21 @@
// FullKillRow.tsx
import React from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import { DetailedKill } from '@/hooks/Mapper/types/kills'; import { DetailedKill } from '@/hooks/Mapper/types/kills';
import { KillRowSubInfo } from './KillRowSubInfo';
import { import {
formatISK, formatISK,
formatTimeMixed, formatTimeMixed,
zkillLink, zkillLink,
getAttackerSubscript, getAttackerSubscript,
buildVictimImageUrls, buildVictimImageUrls,
buildAttackerShipUrl, buildAttackerImageUrls,
getPrimaryLogoAndTooltip,
getAttackerPrimaryImageAndTooltip,
} from '../helpers'; } from '../helpers';
import { VictimRowSubInfo } from './VictimRowSubInfo';
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
import classes from './SystemKillRow.module.scss'; import classes from './SystemKillRow.module.scss';
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
export interface FullKillRowProps { export interface FullKillRowProps {
killDetails: DetailedKill; killDetails: DetailedKill;
@@ -20,73 +25,100 @@ export interface FullKillRowProps {
export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => { export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
const { const {
killmail_id, killmail_id = 0,
victim_char_name = '', victim_char_name = '',
victim_alliance_ticker, victim_alliance_ticker = '',
victim_corp_ticker, victim_corp_ticker = '',
victim_ship_name = '', victim_ship_name = '',
victim_char_id, victim_char_id = 0,
victim_corp_id, victim_corp_id = 0,
victim_alliance_id, victim_alliance_id = 0,
victim_ship_type_id, victim_ship_type_id = 0,
victim_corp_name = '',
victim_alliance_name = '',
total_value, final_blow_char_id = 0,
kill_time,
final_blow_char_id,
final_blow_char_name = '', final_blow_char_name = '',
final_blow_alliance_ticker, final_blow_alliance_ticker = '',
final_blow_corp_ticker, final_blow_corp_ticker = '',
final_blow_corp_name = '',
final_blow_alliance_name = '',
final_blow_corp_id = 0,
final_blow_alliance_id = 0,
final_blow_ship_name = '', final_blow_ship_name = '',
final_blow_ship_type_id, final_blow_ship_type_id = 0,
} = killDetails;
const attackerIsNpc = final_blow_char_id == null; total_value = 0,
kill_time = '',
} = killDetails || {};
const victimAffiliation = victim_alliance_ticker || victim_corp_ticker || ''; const attackerIsNpc = final_blow_char_id === 0;
const victimAffiliation = victim_alliance_ticker || victim_corp_ticker;
const attackerAffiliation = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || ''; const attackerAffiliation = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
const killValueFormatted = total_value && total_value > 0 ? `${formatISK(total_value)} ISK` : null; const killValueFormatted = total_value !== null && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago'; const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
const { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl, victimShipUrl } = buildVictimImageUrls({ const { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
victim_char_id, victim_char_id,
victim_ship_type_id, victim_ship_type_id,
victim_corp_id, victim_corp_id,
victim_alliance_id, victim_alliance_id,
}); });
const { attackerPortraitUrl, attackerCorpLogoUrl, attackerAllianceLogoUrl } = buildAttackerImageUrls({
final_blow_char_id,
final_blow_corp_id,
final_blow_alliance_id,
});
const finalBlowShipUrl = buildAttackerShipUrl(final_blow_ship_type_id); const { url: victimPrimaryImageUrl, tooltip: victimPrimaryTooltip } = getPrimaryLogoAndTooltip(
victimAllianceLogoUrl,
victimCorpLogoUrl,
victim_alliance_name,
victim_corp_name,
'Victim',
);
const { url: attackerPrimaryImageUrl, tooltip: attackerPrimaryTooltip } = getAttackerPrimaryImageAndTooltip(
attackerIsNpc,
attackerAllianceLogoUrl,
attackerCorpLogoUrl,
final_blow_alliance_name,
final_blow_corp_name,
final_blow_ship_type_id || 0,
);
const attackerSubscript = getAttackerSubscript(killDetails); const attackerSubscript = getAttackerSubscript(killDetails);
return ( return (
<div className={clsx(classes.killRowContainer, 'h-18 w-full justify-between items-start text-sm py-[4px]')}> <div className={clsx(classes.killRowContainer, 'h-18 w-full justify-between items-start text-sm py-[4px]')}>
{/* ---------------- Victim Side ---------------- */}
<div className="flex items-start gap-1 min-w-0 h-full"> <div className="flex items-start gap-1 min-w-0 h-full">
{victimShipUrl && ( {/* Victim top-level logo (corp or alliance), with tooltip */}
<div className="relative shrink-0 w-14 h-14 overflow-hidden"> {victimPrimaryImageUrl && (
<a <WdTooltipWrapper content={victimPrimaryTooltip} position={TooltipPosition.top}>
href={zkillLink('kill', killmail_id)} <div className="relative shrink-0 w-14 h-14 overflow-hidden">
target="_blank" <a
rel="noopener noreferrer" href={zkillLink('kill', killmail_id)}
className="block w-full h-full" target="_blank"
> rel="noopener noreferrer"
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} /> className="block w-full h-full"
</a> >
</div> <img
src={victimPrimaryImageUrl}
alt="VictimPrimaryLogo"
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
/>
</a>
</div>
</WdTooltipWrapper>
)} )}
<VictimRowSubInfo
<div className="flex items-start h-14 gap-1 shrink-0"> victimCharName={victim_char_name}
<KillRowSubInfo victimCharacterId={victim_char_id}
victimCorpId={victim_corp_id} victimPortraitUrl={victimPortraitUrl}
victimCorpLogoUrl={victimCorpLogoUrl} />
victimAllianceId={victim_alliance_id}
victimAllianceLogoUrl={victimAllianceLogoUrl}
victimCharacterId={victim_char_id}
victimPortraitUrl={victimPortraitUrl}
/>
</div>
<div className="flex flex-col text-stone-200 leading-4 min-w-0 overflow-hidden"> <div className="flex flex-col text-stone-200 leading-4 min-w-0 overflow-hidden">
<div className="truncate"> <div className="truncate">
<span className="font-semibold">{victim_char_name}</span> <span className="font-semibold">{victim_char_name}</span>
@@ -105,7 +137,7 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
</div> </div>
</div> </div>
<div className="flex items-start gap-2 min-w-0 h-full"> <div className="flex items-start gap-1 min-w-0 h-full">
<div className="flex flex-col items-end leading-4 min-w-0 overflow-hidden text-right"> <div className="flex flex-col items-end leading-4 min-w-0 overflow-hidden text-right">
{!attackerIsNpc && ( {!attackerIsNpc && (
<div className="truncate font-semibold"> <div className="truncate font-semibold">
@@ -118,23 +150,47 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
)} )}
<div className="truncate text-red-400">{killTimeAgo}</div> <div className="truncate text-red-400">{killTimeAgo}</div>
</div> </div>
{finalBlowShipUrl && (
{!attackerIsNpc && attackerPortraitUrl && final_blow_char_id !== null && final_blow_char_id > 0 && (
<div className="relative shrink-0 w-14 h-14 overflow-hidden"> <div className="relative shrink-0 w-14 h-14 overflow-hidden">
<a <a
href={zkillLink('kill', killmail_id)} href={zkillLink('character', final_blow_char_id)}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="block w-full h-full" className="block w-full h-full"
> >
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} /> <img
{attackerSubscript && ( src={attackerPortraitUrl}
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}> alt="AttackerPortrait"
{attackerSubscript.label} className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
</span> />
)}
</a> </a>
</div> </div>
)} )}
{attackerPrimaryImageUrl && (
<WdTooltipWrapper content={attackerPrimaryTooltip} position={TooltipPosition.top}>
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
<a
href={zkillLink('kill', killmail_id)}
target="_blank"
rel="noopener noreferrer"
className="block w-full h-full"
>
<img
src={attackerPrimaryImageUrl}
alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
/>
{attackerSubscript && (
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}>
{attackerSubscript.label}
</span>
)}
</a>
</div>
</WdTooltipWrapper>
)}
</div> </div>
</div> </div>
); );

View File

@@ -1,77 +0,0 @@
import React from 'react';
import clsx from 'clsx';
import { zkillLink } from '../helpers';
import classes from './SystemKillRow.module.scss';
interface KillRowSubInfoProps {
victimCorpId: number | null | undefined;
victimCorpLogoUrl: string | null;
victimAllianceId: number | null | undefined;
victimAllianceLogoUrl: string | null;
victimCharacterId: number | null | undefined;
victimPortraitUrl: string | null;
}
export const KillRowSubInfo: React.FC<KillRowSubInfoProps> = ({
victimCorpId,
victimCorpLogoUrl,
victimAllianceId,
victimAllianceLogoUrl,
victimCharacterId,
victimPortraitUrl,
}) => {
const hasAnything = victimPortraitUrl || victimCorpLogoUrl || victimAllianceLogoUrl;
if (!hasAnything) {
return null;
}
return (
<div className="flex items-start gap-1 h-full">
{victimPortraitUrl && victimCharacterId && (
<a
href={zkillLink('character', victimCharacterId)}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 h-full"
>
<img
src={victimPortraitUrl}
alt="VictimPortrait"
className={clsx(classes.killRowImage, 'h-full w-auto object-contain')}
/>
</a>
)}
<div className="flex flex-col h-full justify-between">
{victimCorpLogoUrl && victimCorpId && (
<a
href={zkillLink('corporation', victimCorpId)}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 h-[26px]"
>
<img
src={victimCorpLogoUrl}
alt="VictimCorp"
className={clsx(classes.killRowImage, 'w-auto h-full object-contain')}
/>
</a>
)}
{victimAllianceLogoUrl && victimAllianceId && (
<a
href={zkillLink('alliance', victimAllianceId)}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 h-[26px]"
>
<img
src={victimAllianceLogoUrl}
alt="VictimAlliance"
className={clsx(classes.killRowImage, 'w-auto h-full object-contain')}
/>
</a>
)}
</div>
</div>
);
};

View File

@@ -1,10 +1,8 @@
.killRowContainer { .killRowContainer {
@apply flex items-center whitespace-nowrap overflow-hidden; @apply flex items-center whitespace-nowrap overflow-hidden;
&:not(:last-child) { &:not(:last-child) {
@apply border-b border-stone-800; @apply border-b border-stone-800;
} }
@apply bg-transparent transition-all hover:bg-stone-900 hover:border-stone-700; @apply bg-transparent transition-all hover:bg-stone-900 hover:border-stone-700;
} }

View File

@@ -54,7 +54,6 @@ export const KillsSettingsDialog: React.FC<KillsSettingsDialogProps> = ({ visibl
}, []); }, []);
const handleAddSystemSubmit: SearchOnSubmitCallback = useCallback(item => { const handleAddSystemSubmit: SearchOnSubmitCallback = useCallback(item => {
if (localRef.current.excludedSystems.includes(item.value)) { if (localRef.current.excludedSystems.includes(item.value)) {
return; return;
} }

View File

@@ -0,0 +1,40 @@
// VictimSubRowInfo.tsx
import React from 'react';
import clsx from 'clsx';
import { zkillLink } from '../helpers';
import classes from './SystemKillRow.module.scss';
interface VictimRowSubInfoProps {
victimCharacterId: number | null;
victimPortraitUrl: string | null;
victimCharName?: string;
}
export const VictimRowSubInfo: React.FC<VictimRowSubInfoProps> = ({
victimCharacterId = 0,
victimPortraitUrl,
victimCharName,
}) => {
if (!victimPortraitUrl || victimCharacterId === null || victimCharacterId <= 0) {
return null;
}
return (
<div className="flex items-start gap-1 h-14">
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
<a
href={zkillLink('character', victimCharacterId)}
target="_blank"
rel="noopener noreferrer"
className="block w-full h-full"
>
<img
src={victimPortraitUrl}
alt={victimCharName || 'Victim Portrait'}
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
/>
</a>
</div>
</div>
);
};

View File

@@ -33,10 +33,6 @@ export function formatISK(value: number): string {
return Math.round(value).toString(); return Math.round(value).toString();
} }
/**
* Determines whether this was an NPC kill, solo kill, etc.
* Returns { label: string, cssClass: string } for display, or null if none.
*/
export function getAttackerSubscript(kill: DetailedKill) { export function getAttackerSubscript(kill: DetailedKill) {
if (kill.npc) { if (kill.npc) {
return { label: 'npc', cssClass: 'text-purple-400' }; return { label: 'npc', cssClass: 'text-purple-400' };

View File

@@ -50,3 +50,62 @@ export function buildVictimImageUrls(args: {
export function buildAttackerShipUrl(final_blow_ship_type_id?: number | null): string | null { export function buildAttackerShipUrl(final_blow_ship_type_id?: number | null): string | null {
return eveImageUrl('types', final_blow_ship_type_id, 'render', 64); return eveImageUrl('types', final_blow_ship_type_id, 'render', 64);
} }
export function buildAttackerImageUrls(args: {
final_blow_char_id?: number | null;
final_blow_corp_id?: number | null;
final_blow_alliance_id?: number | null;
}) {
const { final_blow_char_id, final_blow_corp_id, final_blow_alliance_id } = args;
const attackerPortraitUrl = eveImageUrl('characters', final_blow_char_id, 'portrait', 64);
const attackerCorpLogoUrl = eveImageUrl('corporations', final_blow_corp_id, 'logo', 32);
const attackerAllianceLogoUrl = eveImageUrl('alliances', final_blow_alliance_id, 'logo', 32);
return {
attackerPortraitUrl,
attackerCorpLogoUrl,
attackerAllianceLogoUrl,
};
}
export function getPrimaryLogoAndTooltip(
allianceUrl: string | null,
corpUrl: string | null,
allianceName: string,
corpName: string,
fallback: string,
) {
let url: string | null = null;
let tooltip = '';
if (allianceUrl) {
url = allianceUrl;
tooltip = allianceName || fallback;
} else if (corpUrl) {
url = corpUrl;
tooltip = corpName || fallback;
}
return { url, tooltip };
}
export function getAttackerPrimaryImageAndTooltip(
isNpc: boolean,
allianceUrl: string | null,
corpUrl: string | null,
allianceName: string,
corpName: string,
finalBlowShipTypeId: number,
npcFallback: string = 'NPC Attacker',
) {
if (isNpc) {
const shipUrl = buildAttackerShipUrl(finalBlowShipTypeId);
return {
url: shipUrl,
tooltip: npcFallback,
};
}
return getPrimaryLogoAndTooltip(allianceUrl, corpUrl, allianceName, corpName, 'Attacker');
}

View File

@@ -14,17 +14,22 @@ export interface DetailedKill {
victim_char_name?: string; victim_char_name?: string;
victim_corp_id?: number | null; victim_corp_id?: number | null;
victim_corp_ticker?: string; victim_corp_ticker?: string;
victim_corp_name?: string;
victim_alliance_id?: number | null; victim_alliance_id?: number | null;
victim_alliance_ticker?: string; victim_alliance_ticker?: string;
victim_alliance_name?: string;
victim_ship_type_id?: number | null; victim_ship_type_id?: number | null;
victim_ship_name?: string; victim_ship_name?: string;
final_blow_char_id?: number | null; final_blow_char_id?: number | null;
final_blow_char_name?: string; final_blow_char_name?: string;
final_blow_corp_id?: number | null; final_blow_corp_id?: number | null;
final_blow_corp_ticker?: string; final_blow_corp_ticker?: string;
final_blow_corp_name?: string;
final_blow_alliance_id?: number | null; final_blow_alliance_id?: number | null;
final_blow_alliance_ticker?: string; final_blow_alliance_ticker?: string;
final_blow_alliance_name?: string;
final_blow_ship_type_id?: number | null; final_blow_ship_type_id?: number | null;
final_blow_ship_name?: string; final_blow_ship_name?: string;

View File

@@ -231,19 +231,21 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|> enrich_final_blow() |> enrich_final_blow()
end end
defp enrich_victim(km) do defp enrich_victim(km) do
km km
|> maybe_put_character_name("victim_char_id", "victim_char_name") |> maybe_put_character_name("victim_char_id", "victim_char_name")
|> maybe_put_corp_ticker("victim_corp_id", "victim_corp_ticker") |> maybe_put_corp_info("victim_corp_id", "victim_corp_ticker", "victim_corp_name")
|> maybe_put_alliance_ticker("victim_alliance_id", "victim_alliance_ticker") |> maybe_put_alliance_info("victim_alliance_id", "victim_alliance_ticker", "victim_alliance_name")
|> maybe_put_ship_name("victim_ship_type_id", "victim_ship_name") |> maybe_put_ship_name("victim_ship_type_id", "victim_ship_name")
end end
defp enrich_final_blow(km) do defp enrich_final_blow(km) do
km km
|> maybe_put_character_name("final_blow_char_id", "final_blow_char_name") |> maybe_put_character_name("final_blow_char_id", "final_blow_char_name")
|> maybe_put_corp_ticker("final_blow_corp_id", "final_blow_corp_ticker") |> maybe_put_corp_info("final_blow_corp_id", "final_blow_corp_ticker", "final_blow_corp_name")
|> maybe_put_alliance_ticker("final_blow_alliance_id", "final_blow_alliance_ticker") |> maybe_put_alliance_info("final_blow_alliance_id", "final_blow_alliance_ticker", "final_blow_alliance_name")
|> maybe_put_ship_name("final_blow_ship_type_id", "final_blow_ship_name") |> maybe_put_ship_name("final_blow_ship_type_id", "final_blow_ship_name")
end end
@@ -262,14 +264,16 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
end end
end end
defp maybe_put_corp_ticker(km, id_key, ticker_key) do defp maybe_put_corp_info(km, id_key, ticker_key, name_key) do
case Map.get(km, id_key) do case Map.get(km, id_key) do
nil -> km nil -> km
0 -> km 0 -> km
corp_id -> corp_id ->
case WandererApp.Esi.get_corporation_info(corp_id) do case WandererApp.Esi.get_corporation_info(corp_id) do
{:ok, %{"ticker" => ticker}} -> {:ok, %{"ticker" => ticker, "name" => corp_name}} ->
Map.put(km, ticker_key, ticker) km
|> Map.put(ticker_key, ticker)
|> Map.put(name_key, corp_name)
{:error, reason} -> {:error, reason} ->
Logger.warning("[Parser] Failed to fetch corp info: ID=#{corp_id}, reason=#{inspect(reason)}") Logger.warning("[Parser] Failed to fetch corp info: ID=#{corp_id}, reason=#{inspect(reason)}")
@@ -281,14 +285,16 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
end end
end end
defp maybe_put_alliance_ticker(km, id_key, ticker_key) do defp maybe_put_alliance_info(km, id_key, ticker_key, name_key) do
case Map.get(km, id_key) do case Map.get(km, id_key) do
nil -> km nil -> km
0 -> km 0 -> km
alliance_id -> alliance_id ->
case WandererApp.Esi.get_alliance_info(alliance_id) do case WandererApp.Esi.get_alliance_info(alliance_id) do
{:ok, %{"ticker" => alliance_ticker}} -> {:ok, %{"ticker" => alliance_ticker, "name" => alliance_name}} ->
Map.put(km, ticker_key, alliance_ticker) km
|> Map.put(ticker_key, alliance_ticker)
|> Map.put(name_key, alliance_name)
_ -> _ ->
km km