QHC5AM3DSLRYPRDCQEP4UAGQKRASBKRHJM6FOGNZWNTTO6RYMTNAC
IT55ASWSZHHHW7MZ6MWVFZFZZNA3WKFBXQLNAFY7PYGHYQUJOZIAC
B7W4Q522DLB6DKH2TFDOCTSZFZLFTOLCT6CCZEOC3V3UUMSAOOFAC
N7TZV5WJKLYKSG6SIVAID4ZCC76YHZU5U5WWQGG6TFKAV6CE3Y6AC
HXRDRHIVGSBEAMTKJFZK43MSB53BKON6F77AARUQNWFUPSTZSBPAC
AJKCAY3ODMTFBO6GXWXWQSWNFIH3H7JNBRFVW5H6ZSWA7SZGY3FAC
7QS7R2ORWCZMTCE3SD5PJ5ZL27N3RS7YCWBHXH3JDPTHDQ3KBAMQC
Q4BYGYNX3UZXX47EMX2GWX6M6ICSMIMCLQ7HVOYS4HB4RHYI4NEQC
BZWC6XMOUXEPOI7P65MREJZ45TSQRFMMR2SQ7LML7RMCKUL57VHAC
GGREOYIRZE2GH62X7YXQA7IUSSB25ENLQ5OKVJYWPNI462DP37FAC
fight.map(|fight| NewFight {
log: log.iid,
id: fight.id as i32,
start_time: fight.start_time as i32,
end_time: fight.end_time as i32,
encounter_id: fight.encounter_id as i32,
difficulty: fight.difficulty.map(|d| d as i32),
boss_pct: fight.fight_percentage.map(|p| p as f32),
kill: fight.kill.unwrap_or(false),
avg_ilvl: fight.average_item_level.map(|ilvl| ilvl as f32),
fight.and_then(|fight| {
if fight.size.unwrap_or(5) >= 10 {
Some(NewFight {
log: log.iid,
id: fight.id as i32,
start_time: fight.start_time as i32,
end_time: fight.end_time as i32,
encounter_id: fight.encounter_id as i32,
difficulty: fight.difficulty.map(|d| d as i32),
boss_pct: fight.fight_percentage.map(|p| p as f32),
kill: fight.kill.unwrap_or(false),
avg_ilvl: fight.average_item_level.map(|ilvl| ilvl as f32),
})
} else {
None
}
export function formatRaidTime(day_of_week: number, utc_time: string): Result<{ time: string; day: string; }, 'invalid data'> {
const date = new Date(`January ${3 + day_of_week}, 2021, ${utc_time} GMT+00:00`);
if (date) {
return Ok({
time: new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: 'numeric', timeZoneName: 'short' }).format(date),
day: new Intl.DateTimeFormat('en-US', { weekday: 'short' }).format(date),
});
export function formatRaidTime(rn: RaidNight): Result<string, 'invalid data'> {
const start_date = time_date(rn.startTime, rn.dayOfWeek);
const end_date = time_date(rn.endTime);
if (start_date.ok && end_date.ok) {
const day = new Intl.DateTimeFormat('en-US', { weekday: 'short' }).format(start_date.val);
const start = new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: 'numeric' }).format(start_date.val);
const end = new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: 'numeric', timeZoneName: 'short' }).format(end_date.val);
return Ok(`${day} ${start} - ${end}`);
const nights = data.teamStats.raidNights.filter((rn: RaidNight) => rn.observedInstances >= threshold);
const mins = nights.reduce((sum: number, rn: RaidNight) => {
const start = time_date(rn.startTime, rn.dayOfWeek).unwrap();
let end = time_date(rn.endTime, rn.dayOfWeek).unwrap();
// if end is e.g. 1am while start is 10pm, this can occur with
// the above construction. fix it by incrementing the date
if(end.valueOf() < start.valueOf()) {
end = time_date(rn.endTime, rn.dayOfWeek + 1).unwrap();
}
return sum + (end.valueOf() - start.valueOf());
}, 0) / 1000 / 60;
<section>
<legend className="text-2xl">
Team Overview
</legend>
<dl>
<dt>Bosses Killed:</dt>
<dd>{data.teamStats.bossesKilled}</dd>
<dt>Raid Times:</dt>
<section className="text-xl">
<dl className="grid grid-cols-labels whitespace-nowrap gap-x-5">
<dt className="font-bold">Progress:</dt>
<dd>{data.teamStats.bossesKilled} / {props.encounters.length} {DIFFICULTY_NAMES[5][0]}</dd>
<dt className="font-bold">Raid Times:</dt>
<dd>
{nights.map((rn: RaidNight) => {
return <div>{formatRaidTime(rn).unwrap()}</div>;
})}
</dd>
<dt className="font-bold">
Hours / Week:
</dt>
<table>
<tbody>
{data.teamStats.raidNights.filter((rn: RaidNight) => rn.observedInstances >= threshold).map((rn: RaidNight) => {
const { day } = formatRaidTime(rn.dayOfWeek, rn.startTime).unwrap();
return (
<tr key={rn.dayOfWeek}><td>{day}</td><td>{formatRaidTime(rn.dayOfWeek, rn.startTime).unwrap().time}</td><td>{formatRaidTime(rn.dayOfWeek, rn.endTime).unwrap().time}</td></tr>
);
})}
</tbody>
</table>
{`${Math.floor(mins / 60)}h ${Math.floor(mins % 60)}m`}