Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 95 additions & 102 deletions backend/poetry.lock

Large diffs are not rendered by default.

Binary file added frontend/.yarnrc.yml
Binary file not shown.
32 changes: 17 additions & 15 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"lint": "eslint . --config eslint.config.mjs --fix --max-warnings=0",
"lint:check": "eslint . --config eslint.config.mjs --max-warnings=0",
"start": "next start",
"test:e2e": "npx playwright test",
"test:unit": "tsc --noEmit && NODE_OPTIONS='--experimental-vm-modules --no-warnings=DEP0040' jest"
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"test:unit": "tsc --noEmit && cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"test:e2e": "npx playwright test"
},
"dependencies": {
"@apollo/client": "^3.13.8",
Expand All @@ -26,13 +27,13 @@
"@heroui/react": "^2.8.1",
"@heroui/select": "^2.4.24",
"@heroui/skeleton": "^2.2.15",
"@heroui/system": "^2.4.19",
"@heroui/theme": "^2.4.19",
"@heroui/toast": "^2.0.13",
"@heroui/tooltip": "^2.2.20",
"@next/eslint-plugin-next": "^15.4.3",
"@next/third-parties": "^15.4.3",
"@sentry/nextjs": "^9.40.0",
"@heroui/system": "^2.4.20",
"@heroui/theme": "^2.4.20",
"@heroui/toast": "^2.0.14",
"@heroui/tooltip": "^2.2.21",
"@next/eslint-plugin-next": "^15.4.5",
"@next/third-parties": "^15.4.5",
"@sentry/nextjs": "^9.43.0",
"@testing-library/user-event": "^14.6.1",
"@types/leaflet.markercluster": "^1.5.5",
"@types/lodash": "^4.17.20",
Expand Down Expand Up @@ -65,9 +66,9 @@
"devDependencies": {
"@axe-core/react": "^4.10.2",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.31.0",
"@eslint/js": "^9.32.0",
"@playwright/test": "^1.54.1",
"@swc/core": "^1.13.2",
"@swc/core": "^1.13.3",
"@swc/jest": "^0.2.39",
"@tailwindcss/postcss": "^4.1.11",
"@testing-library/jest-dom": "^6.6.3",
Expand All @@ -83,8 +84,9 @@
"@typescript-eslint/eslint-plugin": "^8.38.0",
"@typescript-eslint/parser": "^8.38.0",
"autoprefixer": "^10.4.21",
"eslint": "^9.31.0",
"eslint-config-next": "^15.4.3",
"cross-env": "^10.0.0",
"eslint": "^9.32.0",
"eslint-config-next": "^15.4.5",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-jest": "^29.0.1",
Expand All @@ -104,11 +106,11 @@
"prettier-plugin-tailwindcss": "^0.6.14",
"require-in-the-middle": "^7.5.2",
"tailwindcss": "^3.4.17",
"ts-jest": "^29.4.0",
"ts-node": "^10.9.2",
"typescript": "^5.8.3",
"typescript-eslint": "^8.38.0",
"util": "^0.12.5"
"util": "^0.12.5",
"which": "^2.0.2"
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

Version mismatch for 'which' package.

The which package version in frontend/package.json is ^2.0.2, but the root package.json specifies ^5.0.0. This inconsistency could lead to conflicts.

#!/bin/bash
# Check for potential conflicts between which package versions
echo "Checking 'which' package versions and compatibility..."
npm view which versions --json | jq '.[-10:]'
echo ""
echo "Checking for breaking changes between v2 and v5..."
curl -s https://registry.npmjs.org/which | jq '.versions["2.0.2"], .versions["5.0.0"]' 2>/dev/null || echo "Could not fetch version details"

Consider standardizing on one version across both package.json files.

🤖 Prompt for AI Agents
In frontend/package.json at line 113, the version of the 'which' package is set
to ^2.0.2, which conflicts with the root package.json that uses ^5.0.0. To fix
this, update the 'which' package version in frontend/package.json to ^5.0.0 to
ensure consistency and avoid potential conflicts across the project.

},
"engines": {
"node": "22"
Expand Down
397 changes: 138 additions & 259 deletions frontend/pnpm-lock.yaml

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions frontend/src/components/AnimatedCounter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import AnimatedCounter from './AnimatedCounter';
import '@testing-library/jest-dom';
import { act } from '@testing-library/react';
describe('AnimatedCounter', () => {
it('renders the counter with the correct value after animation', async () => {
render(<AnimatedCounter end={42} duration={0.1} />);

const counterElement = screen.getByRole('status', { name: /animated counter/i });
expect(counterElement).toBeInTheDocument();

await waitFor(() => {
expect(counterElement.textContent).toBe('42');
}, { timeout: 500 });
});
});
Comment on lines +6 to +17
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

Fix the unimplemented waitFor function.

This test uses waitFor but the function is not imported and the stub implementation at the bottom throws an error.

+import { render, screen, waitFor } from '@testing-library/react';
-import { render, screen } from '@testing-library/react';

Also remove the stub function at lines 71-73.

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

🤖 Prompt for AI Agents
In frontend/src/components/AnimatedCounter.test.tsx around lines 6 to 17, the
test uses the waitFor function but it is not imported, and there is a stub
implementation at lines 71-73 that throws an error. Fix this by importing
waitFor from the testing library at the top of the file and remove the stub
waitFor function at lines 71-73 to ensure the test runs correctly.



describe('AnimatedCounter', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});

it('renders without crashing', () => {
render(<AnimatedCounter end={100} duration={1000} />);
expect(screen.getByRole('status')).toBeInTheDocument();
});

it('renders initial value as 0', () => {
render(<AnimatedCounter end={100} duration={1000} />);
expect(screen.getByText('0')).toBeInTheDocument();
});

it('animates from 0 to end value over time', () => {
render(<AnimatedCounter end={100} duration={1000} />);
act(() => {
jest.advanceTimersByTime(500);
});
const midValue = parseInt(screen.getByRole('status').textContent || '', 10);
expect(midValue).toBeGreaterThan(0);
expect(midValue).toBeLessThan(100);

act(() => {
jest.advanceTimersByTime(500);
});
expect(screen.getByText('100')).toBeInTheDocument();
});

it('handles duration 0 (renders instantly)', () => {
render(<AnimatedCounter end={42} duration={0} />);
expect(screen.getByText('42')).toBeInTheDocument();
});

it('does not animate if start and end are equal', () => {
render(<AnimatedCounter end={50} duration={1000} />);
expect(screen.getByText('50')).toBeInTheDocument();
});
Comment on lines +60 to +63
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

Fix the test logic for equal start and end values.

The test "does not animate if start and end are equal" is incorrect. The component starts at 0 and animates to the end value (50), so it will animate.

-  it('does not animate if start and end are equal', () => {
-  render(<AnimatedCounter end={50} duration={1000} />);
-    expect(screen.getByText('50')).toBeInTheDocument();
-  });
+  it('does not animate if start and end are equal', () => {
+    render(<AnimatedCounter end={0} duration={1000} />);
+    expect(screen.getByText('0')).toBeInTheDocument();
+  });
🤖 Prompt for AI Agents
In frontend/src/components/AnimatedCounter.test.tsx around lines 60 to 63, the
test incorrectly assumes no animation occurs when start and end values are
equal, but the component always animates from 0 to the end value. Update the
test to reflect that animation happens even if start equals end by either
removing the test or adjusting it to check for animation behavior starting from
0 to the end value.


it('has proper accessibility attributes', () => {
render(<AnimatedCounter end={10} duration={1000} />);
const counter = screen.getByRole('status');
expect(counter).toHaveAttribute('aria-label');
});
});
function waitFor(arg0: () => void, arg1: { timeout: number; }) {
throw new Error('Function not implemented.');
}
Comment on lines +71 to +73
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

Remove the stub waitFor function.

This stub function will cause runtime errors and is unnecessary if you import waitFor from @testing-library/react.

-function waitFor(arg0: () => void, arg1: { timeout: number; }) {
-  throw new Error('Function not implemented.');
-}
📝 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
function waitFor(arg0: () => void, arg1: { timeout: number; }) {
throw new Error('Function not implemented.');
}
🤖 Prompt for AI Agents
In frontend/src/components/AnimatedCounter.test.tsx around lines 71 to 73,
remove the stub implementation of the waitFor function entirely. Instead, import
waitFor from '@testing-library/react' at the top of the test file to avoid
runtime errors and use the proper testing utility.


28 changes: 23 additions & 5 deletions frontend/src/components/AnimatedCounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ import millify from 'millify'
import { useEffect, useRef, useState } from 'react'

interface AnimatedCounterProps {
className?: string
duration: number
end: number
duration: number
className?: string
'aria-label'?: string
onEnd?: () => void
}

export default function AnimatedCounter({ end, duration, className }: AnimatedCounterProps) {
export default function AnimatedCounter({
end,
duration,
className,
onEnd,
'aria-label': ariaLabel,
}: AnimatedCounterProps) {
const [count, setCount] = useState(0)
const countRef = useRef(count)
const startTime = useRef(Date.now())
Expand All @@ -25,11 +33,21 @@ export default function AnimatedCounter({ end, duration, className }: AnimatedCo

if (progress < 1) {
requestAnimationFrame(animate)
} else {
if (onEnd) onEnd()
}
}

requestAnimationFrame(animate)
}, [end, duration])
}, [end, duration, onEnd])

return <span className={className}>{millify(count)}</span>
return (
<span
className={className}
role="status"
aria-label={ariaLabel || 'animated counter'}
>
{millify(count)}
</span>
)
}
1 change: 1 addition & 0 deletions frontend/src/sentry.server.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Sentry from '@sentry/nextjs'
import { SENTRY_DSN, ENVIRONMENT, RELEASE_VERSION } from 'utils/credentials'


Sentry.init({
dsn: SENTRY_DSN || '',
enabled: !!SENTRY_DSN,
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"which": "^5.0.0"
}
}
Comment on lines +1 to +5
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Clarify the purpose of this standalone package.json.

This minimal package.json with only a which devDependency seems unusual, especially since which is also added to frontend/package.json. Consider whether this separate file is necessary or if it could be consolidated.


🏁 Script executed:

#!/bin/bash
# Check if this is part of a workspace setup and verify package security
echo "Checking for workspace configuration..."
find . -name "package.json" -exec echo "Found: {}" \;
echo ""
echo "Checking for yarn/npm workspace files..."
ls -la | grep -E "(yarn\.lock|package-lock\.json|pnpm-lock\.yaml|\.yarnrc|\.npmrc)"
echo ""
echo "Verifying 'which' package security advisories..."
curl -s https://registry.npmjs.org/which | jq '.versions | keys | .[-5:]'

Length of output: 737


🏁 Script executed:

#!/bin/bash
echo "Root package.json content (first 50 lines):"
sed -n '1,50p' package.json
echo ""
echo "Checking for workspaces field in root package.json:"
grep -n '"workspaces"' package.json || echo "No workspaces field found"

Length of output: 396


Remove or consolidate the redundant root package.json

The root package.json isn’t configured as a workspace (no workspaces field) and only pulls in the which devDependency—yet you also declare which in frontend/package.json. This standalone file appears unused and could be safely consolidated or removed.

• No workspaces field in package.json
• Root contains only "which": "^5.0.0" under devDependencies
pnpm-lock.yaml lives at the repo root but no workspace config is present
frontend/package.json already includes the same which dependency

Suggested action: either delete this root package.json (and rely on frontend/package.json for dev tooling) or fold its devDependencies into your workspace root if you intend to manage shared tooling there.

🤖 Prompt for AI Agents
In package.json lines 1 to 5, the root package.json is redundant as it only
declares the "which" devDependency already present in frontend/package.json and
lacks a workspaces field. To fix this, either delete the root package.json
entirely to rely solely on frontend/package.json for dependencies, or if you
want a shared workspace root, add a "workspaces" field and consolidate
devDependencies there, removing duplicates from frontend/package.json.

32 changes: 32 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.