Skip to content

Commit 85a9093

Browse files
committed
feat: use timesheet as terminology for the sum of PB attempts and add BPS timesheet
1 parent 7955a26 commit 85a9093

10 files changed

Lines changed: 88 additions & 37 deletions

File tree

src/domains/attempt/components/attempts-comparison-table/vertical-attempts-comparison-table.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { F1Cell } from "./f1-cell";
77
import { GridColumn } from "../../../ui/components/grid/grid-column";
88
import { HorizontalDivider } from "../../../ui/components/grid/horizontal-divider";
99
import type { ReferenceRecords } from "../../types/reference-records";
10-
import type { SumTimeRecords } from "../../types/sum-time-records";
10+
import type { TimeRecordsSum } from "../../types/time-records-sum";
1111
import { TimeWidthCell } from "./time-width-cell";
1212
import { cellCss } from "../../../ui/css/cell-css";
1313
import { delta } from "../../utils/delta";
@@ -23,7 +23,7 @@ const sTitle = cellCss({
2323
interface AttemptsComparisonTableProps {
2424
last: Attempt;
2525
referenceRecords: ReferenceRecords;
26-
sumTimeRecords: SumTimeRecords;
26+
timeRecordsSum: TimeRecordsSum;
2727
}
2828

2929
export const VerticalAttemptsComparisonTable: Component<AttemptsComparisonTableProps> = (props) => {
@@ -146,10 +146,10 @@ export const VerticalAttemptsComparisonTable: Component<AttemptsComparisonTableP
146146
</Show>
147147

148148
{/* Line */}
149-
<Cell column={GRID_FULL_COLUMN} text={`Total PB time (${props.sumTimeRecords.trackCount} tracks)`} css={sTitle} />
149+
<Cell column={GRID_FULL_COLUMN} text={`TimeSheet (${props.timeRecordsSum.trackCount} tracks)`} css={sTitle} />
150150

151151
{/* Line */}
152-
<Cell column={GRID_FULL_COLUMN} text={props.sumTimeRecords.time} css={sTime} />
152+
<Cell column={GRID_FULL_COLUMN} text={props.timeRecordsSum.time} css={sTime} />
153153
</GridColumn>
154154
);
155155
};

src/domains/attempt/components/attempts-filter/use-attempts-filter.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ export function useAttemptsFilter<Input extends Record<string, Accessor<Array<At
1818
const tracks = createMemo(() => {
1919
return unique(
2020
Object.values(props.input)
21-
.flatMap((a) => a())
22-
.map((a) => a.raw.track),
21+
.flatMap((attempts) => attempts())
22+
.map((a) => a.raw.track)
23+
.toSorted(),
2324
);
2425
});
2526

src/domains/attempt/compositions/use-attempts.test.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,23 +256,23 @@ describe("getFlattenRecords", () => {
256256
});
257257
});
258258

259-
describe("getSumTimeRecords", () => {
259+
describe("getSplitRecordsSum", () => {
260260
test("ignores tracks that does not have a final time", () => {
261261
const { createAttempt, createSplit } = useBuildAttempt(2);
262262

263-
const { getSumTimeRecords } = createRoot(() =>
263+
const { getSplitRecordsSum } = createRoot(() =>
264264
useAttempts({ version: 1, attempts: [createAttempt({ splits: createSplit("1:10.000") })] }),
265265
);
266266

267-
const sumTimeRecords = getSumTimeRecords();
267+
const sumTimeRecords = getSplitRecordsSum();
268268
expect(sumTimeRecords.time).toBe("00:00.000");
269269
expect(sumTimeRecords.trackCount).toBe(0);
270270
});
271271

272272
test("takes only one time by track", () => {
273273
const { createAttempt, createSplit } = useBuildAttempt(1);
274274

275-
const { getSumTimeRecords } = createRoot(() =>
275+
const { getSplitRecordsSum } = createRoot(() =>
276276
useAttempts({
277277
version: 1,
278278
attempts: [
@@ -282,7 +282,39 @@ describe("getSumTimeRecords", () => {
282282
}),
283283
);
284284

285-
const sumTimeRecords = getSumTimeRecords();
285+
const sumTimeRecords = getSplitRecordsSum();
286+
expect(sumTimeRecords.time).toBe("01:10.000");
287+
expect(sumTimeRecords.trackCount).toBe(1);
288+
});
289+
});
290+
291+
describe("getTimeRecordsSum", () => {
292+
test("ignores tracks that does not have a final time", () => {
293+
const { createAttempt, createSplit } = useBuildAttempt(2);
294+
295+
const { getTimeRecordsSum } = createRoot(() =>
296+
useAttempts({ version: 1, attempts: [createAttempt({ splits: createSplit("1:10.000") })] }),
297+
);
298+
299+
const sumTimeRecords = getTimeRecordsSum();
300+
expect(sumTimeRecords.time).toBe("00:00.000");
301+
expect(sumTimeRecords.trackCount).toBe(0);
302+
});
303+
304+
test("takes only one time by track", () => {
305+
const { createAttempt, createSplit } = useBuildAttempt(1);
306+
307+
const { getTimeRecordsSum } = createRoot(() =>
308+
useAttempts({
309+
version: 1,
310+
attempts: [
311+
createAttempt({ splits: createSplit("1:10.000") }),
312+
createAttempt({ splits: createSplit("1:10.000") }),
313+
],
314+
}),
315+
);
316+
317+
const sumTimeRecords = getTimeRecordsSum();
286318
expect(sumTimeRecords.time).toBe("01:10.000");
287319
expect(sumTimeRecords.trackCount).toBe(1);
288320
});

src/domains/attempt/compositions/use-attempts.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
flatMap,
1010
groupBy,
1111
isDeepEqual,
12+
isDefined,
1213
last,
1314
map,
1415
pipe,
@@ -23,11 +24,11 @@ import type { AttemptEntity } from "../../database/schemas/attempt-entity";
2324
import type { AttemptsEntity } from "../../database/schemas/attempts-entity";
2425
import type { Brand } from "../../_core/utils/brand";
2526
import type { Store } from "solid-js/store";
26-
import type { SumTimeRecords } from "../types/sum-time-records";
2727
import { Time } from "../utils/time";
28+
import type { TimeRecordsSum } from "../types/time-records-sum";
2829
import { createMemo } from "solid-js";
2930

30-
function getRecordsBy<T extends Attempt>(attempts: Array<T>, by: Parameters<typeof groupBy<T>>[0]): Array<T> {
31+
function getRecordsBy(attempts: Array<Attempt>, by: Parameters<typeof groupBy<Attempt>>[0]): Array<Attempt> {
3132
return pipe(
3233
attempts,
3334
groupBy(by),
@@ -45,6 +46,21 @@ const getRecordsByTime = (attempts: Array<Attempt>): Array<Attempt> =>
4546
const getRecordsBySplitTime = (attempts: Array<Attempt>, sIndex: number): Array<Attempt> =>
4647
getRecordsBy(attempts, (attempt) => attempt.splits.at(sIndex)?.time);
4748

49+
const getRecordsSum = (attempts: Array<Attempt>): TimeRecordsSum => {
50+
return pipe(
51+
attempts,
52+
uniqueBy((attempt) => attempt.raw.track),
53+
filter((record): record is Attempt & { time: string } => isDefined(record.time)),
54+
map((record) => Time.parse(record.time) - Time.parse("0:00.000")),
55+
(times) => {
56+
return {
57+
time: Time.formatH(Time.parse("0:00.000") + sum(times)),
58+
trackCount: times.length,
59+
};
60+
},
61+
);
62+
};
63+
4864
// oxlint-disable-next-line explicit-function-return-type explicit-module-boundary-types
4965
function useAttemptsFactory(store: Store<AttemptsEntity>) {
5066
const attempts = createMemo(() => store.attempts.map((attempt) => v.parse(AttemptSchema, attempt)));
@@ -140,18 +156,12 @@ function useAttemptsFactory(store: Store<AttemptsEntity>) {
140156
),
141157
);
142158

143-
const getSumTimeRecords = createMemo<SumTimeRecords>(() => {
144-
return pipe(
145-
getTimeRecords(),
146-
uniqueBy((attempt) => attempt.raw.track),
147-
map((record) => Time.parse(record.time ?? "0:00.000") - Time.parse("0:00.000")),
148-
(times) => {
149-
return {
150-
time: Time.formatH(Time.parse("0:00.000") + sum(times)),
151-
trackCount: times.length,
152-
};
153-
},
154-
);
159+
const getSplitRecordsSum = createMemo<TimeRecordsSum>(() => {
160+
return getRecordsSum(getSplitRecords());
161+
});
162+
163+
const getTimeRecordsSum = createMemo<TimeRecordsSum>(() => {
164+
return getRecordsSum(getTimeRecords());
155165
});
156166

157167
const merge = (...attempts: Array<Array<AttemptEntity>>): Array<AttemptEntity> => {
@@ -167,12 +177,13 @@ function useAttemptsFactory(store: Store<AttemptsEntity>) {
167177
attempts,
168178
lastAttempt,
169179
tracks,
180+
getFlattenRecords,
170181
getTimeRecords,
171182
getTimeRecordsByTrack,
183+
getTimeRecordsSum,
172184
getSplitRecords,
173185
getSplitRecordByTrack,
174-
getFlattenRecords,
175-
getSumTimeRecords,
186+
getSplitRecordsSum,
176187
merge,
177188
};
178189
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export interface SumTimeRecords {
1+
export interface TimeRecordsSum {
22
time: string;
33
trackCount: number;
44
}

src/domains/database/compositions/use-personal-repository.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ function usePersonalRepositorySingleton() {
2525
getFlattenRecords,
2626
getTimeRecords,
2727
getTimeRecordsByTrack,
28+
getTimeRecordsSum,
2829
getSplitRecords,
2930
getSplitRecordByTrack,
30-
getSumTimeRecords,
31+
getSplitRecordsSum,
3132
merge,
3233
} = useAttempts(store);
3334

@@ -97,9 +98,10 @@ function usePersonalRepositorySingleton() {
9798
getAttemptsCountByTrack,
9899
getTimeRecords,
99100
getTimeRecordsByTrack,
101+
getTimeRecordsSum,
100102
getSplitRecords,
101103
getSplitRecordByTrack,
102-
getSumTimeRecords,
104+
getSplitRecordsSum,
103105
shrink,
104106

105107
// JSON

src/domains/obs/compositions/setup-obs-emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function setupObsEmitterSingleton() {
3232
response.data = {
3333
last: last,
3434
references: repositories.getReferenceRecords(last.raw.track),
35-
sumTimeRecords: personal.getSumTimeRecords(),
35+
timeRecordsSum: personal.getTimeRecordsSum(),
3636
};
3737
}
3838

src/domains/obs/compositions/use-obs-broadcast-channel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { type BroadcastChannel, useBroadcastChannel } from "../../_core/compositions/use-broadcast-channel";
22
import type { Attempt } from "../../attempt/schemas/attempt";
33
import type { ReferenceRecords } from "../../attempt/types/reference-records";
4-
import type { SumTimeRecords } from "../../attempt/types/sum-time-records";
4+
import type { TimeRecordsSum } from "../../attempt/types/time-records-sum";
55

66
interface ObsRequest {
77
type: "request";
@@ -12,7 +12,7 @@ export interface ObsResponse {
1212
data?: {
1313
last: Attempt;
1414
references: ReferenceRecords;
15-
sumTimeRecords: SumTimeRecords;
15+
timeRecordsSum: TimeRecordsSum;
1616
};
1717
}
1818

src/domains/obs/popup-obs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const PopupObs: Component = () => {
5858
<VerticalAttemptsComparisonTable
5959
last={result().last}
6060
referenceRecords={omit(result().references, ["FR"])}
61-
sumTimeRecords={result().sumTimeRecords}
61+
timeRecordsSum={result().timeRecordsSum}
6262
/>
6363
)}
6464
</Match>

src/views/results.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,15 @@ export const Results: Component = () => {
4141
<div class={sHeader}>
4242
<AttemptsFilter />
4343
<GridColumn class={sGrid} template="repeat(3, auto)" spacing="small" yAlign="center">
44-
<VerticalDivider />
45-
<Cell text="Sum of all your personal bests" />
44+
<VerticalDivider row={2} />
45+
<Cell text="TimeSheet (PB)" />
4646
<Cell
47-
text={`${personal.getSumTimeRecords().time} (${personal.getSumTimeRecords().trackCount} tracks)`}
47+
text={`${personal.getTimeRecordsSum().time} (${personal.getTimeRecordsSum().trackCount} tracks)`}
48+
css={sTime}
49+
/>
50+
<Cell text="TimeSheet (BPS)" />
51+
<Cell
52+
text={`${personal.getSplitRecordsSum().time} (${personal.getSplitRecordsSum().trackCount} tracks)`}
4853
css={sTime}
4954
/>
5055
</GridColumn>

0 commit comments

Comments
 (0)