Skip to content

enhance(demo-game): improvements for report page - adding benchmarks, fix ordering player decision table, avg decisions over segments#75

Open
jajakob wants to merge 9 commits intodevfrom
jakob/report-improvements
Open

enhance(demo-game): improvements for report page - adding benchmarks, fix ordering player decision table, avg decisions over segments#75
jajakob wants to merge 9 commits intodevfrom
jakob/report-improvements

Conversation

@jajakob
Copy link
Collaborator

@jajakob jajakob commented Nov 27, 2024

Summary by CodeRabbit

  • New Features

    • Introduced new color configurations for benchmarks in performance metrics.
    • Added three new benchmarks: bank, bonds, and stocks.
  • Improvements

    • Enhanced chart rendering with updated data mapping and improved visual clarity.
    • Updated calculations to reflect segment averages for more accurate performance insights.
    • Improved handling and visualization of performance metrics with new benchmark aggregation.

@jajakob jajakob requested a review from rschlaefli November 27, 2024 13:50
@jajakob jajakob self-assigned this Nov 27, 2024
@vercel
Copy link

vercel bot commented Nov 27, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
gbl-uzh ❌ Failed (Inspect) Dec 23, 2024 10:16am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces modifications to the ReportGame component in the apps/demo-game/src/pages/admin/reports/[id].tsx file. It adds new benchmark configurations for performance metrics, expands the logic for computing data per period with a new function, and updates the rendering logic for charts to utilize these configurations. Additionally, it refactors average decision calculations to focus on segment averages. The component maintains its error handling and loading states while enhancing the clarity of visual data representation.

Changes

File Path Change Summary
apps/demo-game/src/pages/admin/reports/[id].tsx - Added new benchmark configurations (absolutePerformanceConfig, accReturnConfig).
- Introduced getBenchmarksPerPeriod function for aggregating benchmark data.
- Updated chart rendering logic to utilize new configurations.
- Refactored average decision calculations to compute segment averages.
- Modified data structure to include segment information.

Possibly related PRs

  • feat(demo-game): improve reports page #70: The changes in this PR enhance the ReportGame component, which is directly related to the modifications made in the main PR that also focuses on the ReportGame component, specifically improving data handling and visualization.
  • feat(demo-game): risk-return and sharpe-ratio charts #73: This PR introduces new metrics and visualizations related to risk and return, which complements the enhancements made in the main PR to the ReportGame component, particularly in terms of data processing and chart rendering.
  • feat(demo-game): display period settings on admin page #74: The modifications in this PR to the ManageGame component include updates to financial data display, which may relate to the overall reporting and metrics enhancements discussed in the main PR.

Suggested reviewers

  • rschlaefli

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (3)
apps/demo-game/src/pages/admin/reports/[id].tsx (3)

127-157: Refactor to eliminate duplication in benchmark configurations

The absolutePerformanceConfig and accReturnConfig objects contain duplicated benchmark configurations. Extracting the common benchmark settings into a separate object will enhance maintainability and reduce potential inconsistencies.

Apply this diff to refactor the benchmark configurations:

+const benchmarkConfig = {
+  bankBenchmark: {
+    label: 'Savings B',
+    color: colors[4],
+  },
+  bondsBenchmark: {
+    label: 'Bonds B',
+    color: colors[5],
+  },
+  stocksBenchmark: {
+    label: 'Stocks B',
+    color: colors[6],
+  },
+  accBankBenchmarkReturn: {
+    label: 'Savings B',
+    color: colors[4],
+  },
+  accBondsBenchmarkReturn: {
+    label: 'Bonds B',
+    color: colors[5],
+  },
+  accStocksBenchmarkReturn: {
+    label: 'Stocks B',
+    color: colors[6],
+  },
+};

 const absolutePerformanceConfig = {
   ...playerConfig,
-  bankBenchmark: {
-    label: 'Savings B',
-    color: colors[4],
-  },
-  bondsBenchmark: {
-    label: 'Bonds B',
-    color: colors[5],
-  },
-  stocksBenchmark: {
-    label: 'Stocks B',
-    color: colors[6],
-  },
+  bankBenchmark: benchmarkConfig.bankBenchmark,
+  bondsBenchmark: benchmarkConfig.bondsBenchmark,
+  stocksBenchmark: benchmarkConfig.stocksBenchmark,
 };

 const accReturnConfig = {
   ...playerConfig,
-  accBankBenchmarkReturn: {
-    label: 'Savings B',
-    color: colors[4],
-  },
-  accBondsBenchmarkReturn: {
-    label: 'Bonds B',
-    color: colors[5],
-  },
-  accStocksBenchmarkReturn: {
-    label: 'Stocks B',
-    color: colors[6],
-  },
+  accBankBenchmarkReturn: benchmarkConfig.accBankBenchmarkReturn,
+  accBondsBenchmarkReturn: benchmarkConfig.accBondsBenchmarkReturn,
+  accStocksBenchmarkReturn: benchmarkConfig.accStocksBenchmarkReturn,
 };

221-228: Use .forEach() instead of .map() for side effects

The .map() method is used here without utilizing its returned array, which is intended for transformation. Since you're performing side effects, consider using .forEach() for better readability and adherence to JavaScript conventions.

Apply this diff to replace .map() with .forEach():

-playerResPerPeriod.map((result) => {
+playerResPerPeriod.forEach((result) => {
   const assetsWithReturns = result.facts.assetsWithReturns.filter(
     (_, ix) => ix > 0
   )
-  Object.keys(dataBenchmark).map((key) => {
+  Object.keys(dataBenchmark).forEach((key) => {
     dataBenchmark[key].push(...assetsWithReturns.map((a) => a[key]))
   })
 })

659-680: Extract tooltip formatter into a reusable function to reduce duplication

The tooltip formatter function is similar across multiple chart components. To enhance code maintainability and readability, consider extracting this formatter into a reusable function or component.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between cdf2d04 and 8467e92.

📒 Files selected for processing (1)
  • apps/demo-game/src/pages/admin/reports/[id].tsx (12 hunks)

Comment on lines +353 to +449
const period = ~~(segmentIx / game.activePeriodIx) + 1
const segment = (segmentIx % game.activePeriodIx) + 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent division by zero when calculating period and segment

The calculation uses game.activePeriodIx as a divisor. If game.activePeriodIx is zero, this will cause a division by zero error. Ensure that game.activePeriodIx is not zero before performing the calculation.

Apply this diff to add a safety check:

 const dataAvg = segmentResultPerSegmentAvg.map((values, segmentIx) => {
+  if (game.activePeriodIx === 0) {
+    console.error('game.activePeriodIx is zero, cannot divide by zero.')
+    return null;
+  }
   const period = Math.floor(segmentIx / game.activePeriodIx) + 1
   const segment = (segmentIx % game.activePeriodIx) + 1

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +51 to +63
// TODO(JJ): Maybe add a random color generator, because we have unkown many teams
const colors = [
'hsl(var(--chart-1))',
'hsl(var(--chart-2))',
'hsl(var(--chart-3))',
'hsl(var(--chart-4))',
'hsl(var(--chart-5))',
'#2b463c',
'#688f4f',
'#b1d182',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement dynamic color generation for unknown team counts

The current implementation uses a static array of colors, which may not suffice when dealing with an unknown number of teams. Consider implementing a dynamic color generator to ensure that each team is assigned a unique color, regardless of the number of teams.

Apply this diff to implement dynamic color generation:

-// TODO(JJ): Maybe add a random color generator, because we have unkown many teams
 const colors = [
   'hsl(var(--chart-1))',
   'hsl(var(--chart-2))',
   'hsl(var(--chart-3))',
   'hsl(var(--chart-4))',
   'hsl(var(--chart-5))',
   '#2b463c',
   '#688f4f',
   '#b1d182',
 ]
+// Generate colors dynamically for unknown number of teams
+const generateColors = (numColors) => {
+  return Array.from({ length: numColors }, (_, i) => `hsl(${(i * (360 / numColors))}, 70%, 50%)`);
+};
+const colors = generateColors(game.players.length);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +235 to +268
const benchmarksFlat = Object.keys(benchmarksPerPeriod[0]).reduce(
(acc, key) => {
acc[key] = benchmarksPerPeriod.flatMap((p) => p[key])
return acc
},
{}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure benchmarksPerPeriod is not empty before accessing index 0

The code assumes that benchmarksPerPeriod[0] exists. If benchmarksPerPeriod is empty, this will result in an error. Add a check to confirm that benchmarksPerPeriod contains data before proceeding.

Apply this diff to add a safety check:

 const benchmarksPerPeriod = getBenchmarksPerPeriod()
+if (benchmarksPerPeriod.length === 0) {
+  console.error('Benchmarks per period is empty.')
+  return null;
+}
 const benchmarksFlat = Object.keys(benchmarksPerPeriod[0]).reduce(
   (acc, key) => {
     acc[key] = benchmarksPerPeriod.flatMap((p) => p[key])
     return acc
   },
   {}
 )

Committable suggestion skipped: line range outside the PR's diff.

@rschlaefli rschlaefli changed the title feat(demo-game): improvements for report page - adding benchmarks, fix ordering player decision table, avg decisions over segments enhance(demo-game): improvements for report page - adding benchmarks, fix ordering player decision table, avg decisions over segments Dec 2, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (2)
apps/demo-game/src/pages/admin/reports/[id].tsx (2)

144-174: Consider using a more maintainable approach for benchmark colors

The configuration objects are well-structured, but they rely on hardcoded color indices (colors[4], colors[5], colors[6]). This makes the code fragile to changes in the colors array.

Consider creating named constants for benchmark colors or using a color generation function:

+const BENCHMARK_COLORS = {
+  SAVINGS: 'hsl(var(--chart-5))',
+  BONDS: '#2b463c',
+  STOCKS: '#688f4f',
+}

 const absolutePerformanceConfig = {
   ...playerConfig,
   bankBenchmark: {
     label: 'Savings B',
-    color: colors[4],
+    color: BENCHMARK_COLORS.SAVINGS,
   },
   // ... similar changes for other benchmarks
 }

271-288: Improve readability of benchmark data integration

The nested reduce operations make the code harder to understand and maintain.

Consider extracting the benchmark key filtering and mapping logic into separate functions:

+const BENCHMARK_KEYS = ['bankBenchmark', 'bondsBenchmark', 'stocksBenchmark'];
+
+const getBenchmarkData = (benchmarksFlat, index) => 
+  BENCHMARK_KEYS.reduce((acc, key) => {
+    acc[key] = benchmarksFlat[key][index];
+    return acc;
+  }, {});

 const dataTotalAssets = composeChartData(dataPerPeriod, 'totalAssets').map(
   (d, ix) => ({
     ...d,
-    ...Object.keys(benchmarksFlat)
-      .filter(key => 
-        key === 'bankBenchmark' ||
-        key === 'bondsBenchmark' ||
-        key === 'stocksBenchmark'
-      )
-      .reduce((acc, key) => {
-        acc[key] = benchmarksFlat[key][ix]
-        return acc
-      }, {}),
+    ...getBenchmarkData(benchmarksFlat, ix)
   })
 )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6fb615a and 146d640.

📒 Files selected for processing (1)
  • apps/demo-game/src/pages/admin/reports/[id].tsx (14 hunks)
🔇 Additional comments (1)
apps/demo-game/src/pages/admin/reports/[id].tsx (1)

Line range hint 469-776: LGTM! Well-implemented chart updates

The chart updates maintain consistency across different visualizations and provide clear formatting for percentage values. The tooltip implementations are particularly well done.

Comment on lines +228 to +259
const getBenchmarksPerPeriod = () => {
if (!previousSegmentResults || previousSegmentResults.length === 0)
return []
let output = []
// The benchmarks are saved for all results, we only need it once for each segment
const player = game.players[0]
for (let i = 0; i < numPeriods; i++) {
const playerResPerPeriod = previousSegmentResults.filter(
(result) =>
result.period.index === i && result.player.id === player.id
)
const dataBenchmark = {
bankBenchmark: [],
bondsBenchmark: [],
stocksBenchmark: [],
accBankBenchmarkReturn: [],
accBondsBenchmarkReturn: [],
accStocksBenchmarkReturn: [],
}

playerResPerPeriod.map((result) => {
const assetsWithReturns = result.facts.assetsWithReturns.filter(
(_, ix) => ix > 0
)
Object.keys(dataBenchmark).map((key) => {
dataBenchmark[key].push(...assetsWithReturns.map((a) => a[key]))
})
})
output.push(dataBenchmark)
}
return output
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for assetsWithReturns

The function assumes result.facts.assetsWithReturns always exists, which could lead to runtime errors.

Add a null check before accessing the property:

 playerResPerPeriod.map((result) => {
+  if (!result.facts.assetsWithReturns) {
+    console.warn('Missing assetsWithReturns for result:', result);
+    return;
+  }
   const assetsWithReturns = result.facts.assetsWithReturns.filter(
     (_, ix) => ix > 0
   )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getBenchmarksPerPeriod = () => {
if (!previousSegmentResults || previousSegmentResults.length === 0)
return []
let output = []
// The benchmarks are saved for all results, we only need it once for each segment
const player = game.players[0]
for (let i = 0; i < numPeriods; i++) {
const playerResPerPeriod = previousSegmentResults.filter(
(result) =>
result.period.index === i && result.player.id === player.id
)
const dataBenchmark = {
bankBenchmark: [],
bondsBenchmark: [],
stocksBenchmark: [],
accBankBenchmarkReturn: [],
accBondsBenchmarkReturn: [],
accStocksBenchmarkReturn: [],
}
playerResPerPeriod.map((result) => {
const assetsWithReturns = result.facts.assetsWithReturns.filter(
(_, ix) => ix > 0
)
Object.keys(dataBenchmark).map((key) => {
dataBenchmark[key].push(...assetsWithReturns.map((a) => a[key]))
})
})
output.push(dataBenchmark)
}
return output
}
const getBenchmarksPerPeriod = () => {
if (!previousSegmentResults || previousSegmentResults.length === 0)
return []
let output = []
// The benchmarks are saved for all results, we only need it once for each segment
const player = game.players[0]
for (let i = 0; i < numPeriods; i++) {
const playerResPerPeriod = previousSegmentResults.filter(
(result) =>
result.period.index === i && result.player.id === player.id
)
const dataBenchmark = {
bankBenchmark: [],
bondsBenchmark: [],
stocksBenchmark: [],
accBankBenchmarkReturn: [],
accBondsBenchmarkReturn: [],
accStocksBenchmarkReturn: [],
}
playerResPerPeriod.map((result) => {
if (!result.facts.assetsWithReturns) {
console.warn('Missing assetsWithReturns for result:', result);
return;
}
const assetsWithReturns = result.facts.assetsWithReturns.filter(
(_, ix) => ix > 0
)
Object.keys(dataBenchmark).map((key) => {
dataBenchmark[key].push(...assetsWithReturns.map((a) => a[key]))
})
})
output.push(dataBenchmark)
}
return output
}

Comment on lines +323 to +335
const segmentResultPerSegmentAvg = segmentResultsPerPlayer[0].map(
(_, i) => {
const numSegments = segmentResultsPerPlayer[0][i].length
const sumPerSegment = segmentResultsPerPlayer
.reduce(
(sum, player) => sum.map((val, idx) => val + player[i][idx]),
Array(numSegments).fill(0)
)
.map((sum) => sum / segmentResultsPerPlayer.length)

const computeTotalDecisionAvg = () => {
const result = Array(segmentResultPerPlayerAvg[0].length).fill(0)
segmentResultPerPlayerAvg.forEach((val) => {
val.forEach((v, i) => {
result[i] += v / segmentResultPerPlayerAvg.length
})
})
return result
}
const totalDecisionAvg = computeTotalDecisionAvg()
return sumPerSegment
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add safety checks and simplify array operations

The average calculation could fail if there are no players, and the array operations could be simplified.

Consider adding safety checks and simplifying the code:

 const segmentResultPerSegmentAvg = segmentResultsPerPlayer[0].map(
   (_, i) => {
+    if (segmentResultsPerPlayer.length === 0) {
+      console.warn('No players available for average calculation');
+      return Array(numSegments).fill(0);
+    }
     const numSegments = segmentResultsPerPlayer[0][i].length
-    const sumPerSegment = segmentResultsPerPlayer
-      .reduce(
-        (sum, player) => sum.map((val, idx) => val + player[i][idx]),
-        Array(numSegments).fill(0)
-      )
-      .map((sum) => sum / segmentResultsPerPlayer.length)
+    const sumPerSegment = Array(numSegments).fill(0).map((_, idx) => 
+      segmentResultsPerPlayer.reduce((sum, player) => 
+        sum + player[i][idx], 0) / segmentResultsPerPlayer.length
+    );
     return sumPerSegment
   }
 )

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Member

@rschlaefli rschlaefli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small things that we should still fix on this branch before merging:

  • Average decision is indexed with P1 S0, P2 S1, ..., and not with correct segments
  • Tooltips for benchmarks should have nice naming
  • The admin reports seem to show results already for the running segment, which is a bit strange, as this should not have been computed yet (it is also the case on the dev branch, but we could fix it on this one)
  • Some other small things

We can also discuss this in January before merging this PR :)

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/demo-game/src/pages/admin/reports/[id].tsx (3)

144-174: Add TypeScript interfaces for configuration objects

Consider adding TypeScript interfaces to define the structure of these configuration objects. This would improve type safety and make the code more maintainable.

interface ChartConfig {
  label: string;
  color: string;
}

interface BenchmarkConfig extends Record<string, ChartConfig> {
  bankBenchmark: ChartConfig;
  bondsBenchmark: ChartConfig;
  stocksBenchmark: ChartConfig;
}

271-288: Optimize data transformation for better readability and performance

The nested map/reduce operations make the code hard to follow. Consider extracting the benchmark filtering logic into a separate function.

+const getBenchmarkKeys = (type: 'absolute' | 'return') => {
+  const keys = {
+    absolute: ['bankBenchmark', 'bondsBenchmark', 'stocksBenchmark'],
+    return: ['accBankBenchmarkReturn', 'accBondsBenchmarkReturn', 'accStocksBenchmarkReturn']
+  }
+  return keys[type]
+}

 const dataTotalAssets = composeChartData(dataPerPeriod, 'totalAssets').map(
   (d, ix) => ({
     ...d,
-    ...Object.keys(benchmarksFlat)
-      .filter(key =>
-        key === 'bankBenchmark' ||
-        key === 'bondsBenchmark' ||
-        key === 'stocksBenchmark'
-      )
+    ...getBenchmarkKeys('absolute')
       .reduce((acc, key) => {
         acc[key] = benchmarksFlat[key][ix]
         return acc
       }, {})
   })
 )

756-777: Extract common tooltip configuration

The tooltip configuration is duplicated across multiple chart components. Consider extracting it into a reusable component or configuration object.

const createTooltipFormatter = (valueFormatter = (v: number) => v.toFixed(2)) => 
  (value: number, name: string, item: any) => [
    <div key={name} className="flex w-full items-center justify-between gap-x-2">
      <div className="flex items-center gap-x-1">
        <div
          className="h-[8px] w-[8px] rounded-sm"
          style={{ background: item.color }}
        />
        <span className="text-xs text-gray-600">
          {name === 'bank' ? 'savings' : name}
        </span>
      </div>
      <span className="font-bold text-black">
        {valueFormatter(value)}
      </span>
    </div>
  ];
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d6e886 and 63293d5.

📒 Files selected for processing (1)
  • apps/demo-game/src/pages/admin/reports/[id].tsx (12 hunks)
🔇 Additional comments (3)
apps/demo-game/src/pages/admin/reports/[id].tsx (3)

54-63: Consider implementing dynamic color generation

The current implementation uses a static array of colors, which may not be sufficient for an unknown number of teams.


448-459: Replace bitwise operation with explicit Math.floor

The use of ~~ for floor division is clever but reduces code readability. Consider using Math.floor instead.

-    const period = ~~(segmentIx / game.activePeriodIx) + 1
+    const period = Math.floor(segmentIx / game.activePeriodIx) + 1

262-268: ⚠️ Potential issue

Add safety check for benchmarksPerPeriod array access

The code assumes benchmarksPerPeriod[0] exists. Add a check to prevent potential runtime errors.

 const benchmarksPerPeriod = getBenchmarksPerPeriod()
+if (!benchmarksPerPeriod.length) {
+  console.warn('No benchmark data available')
+  return { game, playerConfig }
+}
 const benchmarksFlat = Object.keys(benchmarksPerPeriod[0]).reduce(

Likely invalid or redundant comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants