|
1 | 1 | import { useState } from "react"; |
2 | 2 | import { EmptyState } from "./EmptyState"; |
3 | 3 | import { useAppSelector } from "../../../hooks"; |
4 | | -import { formatElapsedTime } from "../../../utils"; |
| 4 | +import { formatElapsedTime, hoursToMs } from "../../../utils"; |
5 | 5 | import { GroupedTimeEntryRow } from "./GroupedTimeEntryRow"; |
6 | 6 | import { |
7 | 7 | selectTimeEntriesGroupedByDate, |
@@ -88,15 +88,11 @@ function DayHeader({ |
88 | 88 | <span className="mr-2 text-lg font-semibold text-neutral-700 opacity-50"> |
89 | 89 | {formatElapsedTime(elapsedTimePerDay)} |
90 | 90 | </span> |
91 | | - |
92 | | - <div className="flex items-center text-xs font-semibold"> |
93 | | - <span className="rounded rounded-r-none border border-neutral-500 bg-neutral-500 pl-2 pr-1 text-white"> |
94 | | - Logged |
95 | | - </span> |
96 | | - <span className="flex items-center rounded rounded-l-none border bg-neutral-100 pl-1 pr-2 text-neutral-700 opacity-50"> |
97 | | - {formatElapsedTime(reportedTimePerDay)} |
98 | | - </span> |
99 | | - </div> |
| 91 | + <LoggedTimeBadge |
| 92 | + label="Logged" |
| 93 | + reportedTimePerDay={reportedTimePerDay} |
| 94 | + targetHours={6} |
| 95 | + /> |
100 | 96 | </div> |
101 | 97 | ); |
102 | 98 | } else { |
@@ -144,3 +140,51 @@ const PaginationButtons = ({ |
144 | 140 | </div> |
145 | 141 | ); |
146 | 142 | }; |
| 143 | + |
| 144 | +// TODO: move to separate file |
| 145 | +export const LoggedTimeBadge = ({ |
| 146 | + label, |
| 147 | + reportedTimePerDay, |
| 148 | + targetHours, |
| 149 | +}: { |
| 150 | + label: string; |
| 151 | + targetHours: number; |
| 152 | + reportedTimePerDay: number; |
| 153 | +}) => { |
| 154 | + const percentage = (reportedTimePerDay / hoursToMs(targetHours)) * 100; |
| 155 | + |
| 156 | + const colors = { |
| 157 | + low: "#ba4244", |
| 158 | + medium: "#d2812c", |
| 159 | + high: "#59b173", |
| 160 | + beyond: "#546cc0", |
| 161 | + }; |
| 162 | + |
| 163 | + return ( |
| 164 | + <div className="relative" title={`${percentage.toFixed(0)}% of target`}> |
| 165 | + <div className="flex items-center text-xs font-semibold"> |
| 166 | + <span className="rounded rounded-r-none rounded-b-none border border-neutral-500 bg-neutral-500 pl-2 pr-1 text-white"> |
| 167 | + {label} |
| 168 | + </span> |
| 169 | + <span className="flex items-center rounded rounded-l-none rounded-b-none border bg-neutral-100 pl-1 pr-2 text-neutral-700 opacity-50"> |
| 170 | + {formatElapsedTime(reportedTimePerDay)} |
| 171 | + </span> |
| 172 | + </div> |
| 173 | + <div className="absolute w-[100%] h-1 rounded-t-none rounded border-0 border-neutral-200 bg-neutral-100"> |
| 174 | + <div |
| 175 | + className={`h-full rounded rounded-t-none`} |
| 176 | + style={{ |
| 177 | + width: `${Math.min(percentage, 100)}%`, |
| 178 | + backgroundColor: |
| 179 | + percentage < 50 |
| 180 | + ? colors.low |
| 181 | + : percentage < 80 |
| 182 | + ? colors.medium |
| 183 | + : colors.high, |
| 184 | + borderBottomRightRadius: percentage < 100 ? "0px" : "4px", |
| 185 | + }} |
| 186 | + /> |
| 187 | + </div> |
| 188 | + </div> |
| 189 | + ); |
| 190 | +}; |
0 commit comments