|
1 | 1 | // 'use client'; |
2 | 2 | import './Timeline.css'; |
| 3 | +import { timeAgo, timeUntil } from '@/utils/time'; |
3 | 4 |
|
4 | 5 | export default function Timeline({ data }) { |
5 | 6 | const events = [...data.defend_events, ...data.attack_events]; |
@@ -35,21 +36,137 @@ function generateEvent(event) { |
35 | 36 | } else { |
36 | 37 | type = 'Attack'; |
37 | 38 | } |
38 | | - const start = new Date(event.start_time * 1000).toLocaleString('en-GB'); |
39 | | - const end = new Date(event.end_time * 1000).toLocaleString('en-GB'); |
| 39 | + |
| 40 | + const start = timeAgo(event.start_time * 1000); |
| 41 | + const end = timeAgo(event.end_time * 1000); |
| 42 | + // const start = new Date(event.start_time * 1000).toLocaleString('en-GB'); |
| 43 | + // const end = new Date(event.end_time * 1000).toLocaleString('en-GB'); |
| 44 | + |
| 45 | + const percent = (event.points / event.points_max) * 100; |
| 46 | + const progress = util_evaluate_progress(event); |
| 47 | + // console.log(event, progress); |
40 | 48 |
|
41 | 49 | return ( |
42 | 50 | <article |
43 | 51 | id="event" |
44 | 52 | key={event.event_id} |
45 | | - className={`flex flex-col gap-2 rounded-sm p-2 ${type} ${event?.status} ${event?.status === 'active' ? 'active' : ''}`} |
| 53 | + className={`relative flex flex-col gap-2 overflow-hidden rounded-sm p-2 ${type} ${event?.status} ${event?.status === 'active' ? 'active' : ''}`} |
46 | 54 | > |
47 | | - <h3>{type} Event</h3> |
48 | | - Started at {start} |
49 | | - <br /> |
50 | | - Finished at {end} |
51 | | - <br /> |
52 | | - {event.status} |
| 55 | + <div className="flex gap-2"> |
| 56 | + <img |
| 57 | + src={`/icons/faction${event?.enemy}.webp`} |
| 58 | + alt="Logo of Helldivers Bot, which is a cartoon depiction of a spy sattelite" |
| 59 | + width={20} |
| 60 | + height={20} |
| 61 | + /> |
| 62 | + <h3>{type} Event</h3> |
| 63 | + </div> |
| 64 | + <div className="z-20 flex flex-col gap-2 text-sm"> |
| 65 | + <div className="flex justify-between gap-2"> |
| 66 | + <span>Started {start}</span> |
| 67 | + {end.includes('ago') ? |
| 68 | + <span>Finished {end}</span> |
| 69 | + : <span>Finishes in {end}</span>} |
| 70 | + </div> |
| 71 | + |
| 72 | + <div>{progress}</div> |
| 73 | + |
| 74 | + <div className="relative"> |
| 75 | + <progress value={percent} max="100" className="h-5 w-full"></progress> |
| 76 | + <span className="absolute left-1 text-black"> |
| 77 | + {event.points} / {event.points_max} |
| 78 | + </span> |
| 79 | + <span className="absolute right-1 text-black"> |
| 80 | + {percent.toFixed(2)}% |
| 81 | + </span> |
| 82 | + </div> |
| 83 | + </div> |
| 84 | + |
| 85 | + <img |
| 86 | + src={`/icons/${type}.webp`} |
| 87 | + alt={`${type} Event Icon`} |
| 88 | + className="absolute -bottom-5 right-0 z-0 h-[80%] opacity-65" |
| 89 | + /> |
53 | 90 | </article> |
54 | 91 | ); |
55 | 92 | } |
| 93 | + |
| 94 | +function util_evaluate_progress(event) { |
| 95 | + // Get the current time as a timestamp |
| 96 | + const currentTime = Math.floor(Date.now() / 1000); |
| 97 | + |
| 98 | + // Calculate total time in milliseconds |
| 99 | + const totalTime = event.end_time - event.start_time; |
| 100 | + // console.log('totalTime', totalTime); |
| 101 | + |
| 102 | + // Calculate elapsed time in milliseconds |
| 103 | + const elapsedTime = currentTime - event.start_time; |
| 104 | + // console.log('elapsedTime', elapsedTime); |
| 105 | + |
| 106 | + // Calculate remaining time in milliseconds |
| 107 | + const remainingTime = event.end_time - currentTime; |
| 108 | + // console.log('remainingTime', remainingTime); |
| 109 | + |
| 110 | + // Calculate the expected rate of progress (points per millisecond) |
| 111 | + const expectedRate = event.points_max / totalTime; |
| 112 | + |
| 113 | + // Calculate the current rate of progress (points per millisecond) |
| 114 | + const currentRate = event.points / elapsedTime; |
| 115 | + |
| 116 | + // Calculate the expected points by now |
| 117 | + const expectedPoints = expectedRate * elapsedTime; |
| 118 | + |
| 119 | + // Calculate the remaining points |
| 120 | + const remainingPoints = event.points_max - event.points; |
| 121 | + |
| 122 | + // Calculate the required rate for the remaining time (points per millisecond) |
| 123 | + const requiredRate = remainingPoints / remainingTime; |
| 124 | + |
| 125 | + // 10% buffer |
| 126 | + const buffer = expectedPoints * 0.1; |
| 127 | + // Determine the progress status |
| 128 | + let status; |
| 129 | + if (event.points > expectedPoints + buffer) { |
| 130 | + status = 'Ahead'; |
| 131 | + } else if (event.points < expectedPoints) { |
| 132 | + status = 'Behind'; |
| 133 | + } else { |
| 134 | + status = 'On track'; |
| 135 | + } |
| 136 | + |
| 137 | + // Determine if the current rate is sufficient |
| 138 | + // let rateStatus; |
| 139 | + // if (currentRate >= requiredRate) { |
| 140 | + // rateStatus = 'on track to meet your goal'; |
| 141 | + // } else { |
| 142 | + // rateStatus = 'need to increase your rate to meet your goal'; |
| 143 | + // } |
| 144 | + |
| 145 | + let pointDifference = Math.abs(expectedPoints - event.points); |
| 146 | + |
| 147 | + const progress = { |
| 148 | + expectedRate: expectedRate.toFixed(6), // Adjust precision as needed |
| 149 | + currentRate: currentRate.toFixed(6), |
| 150 | + expectedPoints: expectedPoints.toFixed(0), |
| 151 | + remainingPoints: remainingPoints.toFixed(0), |
| 152 | + requiredRate: requiredRate.toFixed(6), |
| 153 | + status: status, |
| 154 | + // rateStatus: rateStatus, |
| 155 | + }; |
| 156 | + |
| 157 | + if (event.status === 'active') { |
| 158 | + return `${status} by ${pointDifference.toFixed(0)} points`; |
| 159 | + } |
| 160 | + // if (event.status === 'success') { |
| 161 | + // const remaining_minutes = 120 - Math.floor(elapsedTime / 60); |
| 162 | + // const win_text = |
| 163 | + // remaining_minutes > 1 ? |
| 164 | + // `${remaining_minutes} minutes` |
| 165 | + // : `${remaining_minutes} minute`; |
| 166 | + |
| 167 | + // return `Won with ${win_text} to spare.`; |
| 168 | + // } |
| 169 | + // if (event.status === 'failure') { |
| 170 | + // return `Lost ${pointDifference.toFixed(0)} points`; |
| 171 | + // } |
| 172 | +} |
0 commit comments