Skip to content

Conversation

kasumi-1
Copy link
Contributor

@kasumi-1 kasumi-1 commented Oct 1, 2025

Summary by CodeRabbit

  • New Features
    • Ensured always-fresh data by forcing dynamic rendering on Open Jobs and Post Job pages.
  • UI/Style
    • Replaced rating control with a custom 5‑star widget in approval flow.
    • Improved readability of chat and delivery content (markdown typography, icons).
  • Refactor
    • Migrated app data layer to a new GraphQL client for smoother, more reliable loading across Jobs, Users, and Arbitrators pages.
  • Documentation
    • Switched setup instructions to npm; added project badges; added Lighthouse config.
  • Tests
    • Added extensive unit/integration tests and Vitest setup.
  • Chores/CI
    • Added coverage and Lighthouse CI workflows; enabled Dependabot updates.

- Remove unnecessary console.log statements from production code
- Reorder and organize package.json dependencies
- Add missing dev dependency @rollup/rollup-darwin-arm64
- Upgrade React, Next.js, and related dependencies to React 19 RC versions
- Update type definitions and component implementations for React 19 compatibility
- Remove deprecated experimental instrumentation hook from Next config
- Fix ref initialization and type issues in several components
- Update params handling in server components to support async params
Copy link

vercel bot commented Oct 1, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-effectiveacceleration Ready Ready Preview Comment Oct 5, 2025 10:07am
effectiveacceleration.ai Ready Ready Preview Comment Oct 5, 2025 10:07am

Copy link

coderabbitai bot commented Oct 1, 2025

Warning

Rate limit exceeded

@kasumi-1 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2e74b41 and ebcfa28.

📒 Files selected for processing (1)
  • website/next.config.mjs (1 hunks)

Walkthrough

Migrates the website from Apollo Client to URQL across providers, hooks, and pages; adjusts Next.js route params to async Promises; adds URQL client/server utilities; introduces extensive Vitest-based tests and setup for website and subsquid; updates CI (coverage, Lighthouse) and Dependabot; modifies icons/UI styling; revises contract tests and coverage config.

Changes

Cohort / File(s) Summary
GraphQL client migration (Apollo → URQL)
website/src/app/*/page.tsx, website/src/app/providers.tsx, website/src/hooks/subsquid/*, website/src/hooks/useSwResetMessage.tsx, website/src/hooks/subsquid/queries.ts, website/src/lib/urql-client.ts, website/src/lib/urql-server.ts
Replaced Apollo with URQL: provider swap, query hooks refactor (skip→pause, result.fetching/error), server/client URQL utilities added, cache reset logic removed, gql import moved to graphql-tag, return shapes standardized to { data, loading, error }.
Async route params in Next.js
website/src/app/arbitrators/[address]/page.tsx, website/src/app/jobs/[id]/page.tsx, website/src/app/users/[address]/page.tsx
Updated generateMetadata and page components to accept params as Promise and await values; adapted data fetching accordingly.
Dynamic rendering flags
website/src/app/open-job-list/page.tsx, website/src/app/post-job/page.tsx
Added export const dynamic = 'force-dynamic' to force dynamic rendering.
UI/style adjustments (Markdown and icons)
website/src/app/jobs/[id]/JobChat/**/{DeliveredEvent,OwnerMessageEvent,WorkerMessageEvent}.tsx, website/src/app/jobs/[id]/JobChat/StatusStates/*, website/src/app/jobs/[id]/JobActions/ApproveButton.tsx, website/src/components/TokenSelector/icons/*
Moved text styles from Markdown to wrappers; replaced MUI Rating with custom star buttons; replaced MUI SvgIcon with inline SVG in icons.
Minor code cleanups
website/src/app/jobs/[id]/JobActions/{PostMessageButton,UpdateButton}.tsx, website/src/app/jobs/[id]/JobChat/JobChatStatus.tsx, website/src/app/jobs/[id]/JobChatDetails.tsx, website/src/components/AddToHomescreen.tsx, website/src/components/Dashboard/Navbar/NotificationsButton.tsx
Type tweaks for refs, removed console logs/imports, stopped using refetch from notifications hook, minor ref initializations.
Binary Blob handling
website/src/hooks/{useFetchAvatar.tsx,useMediaDownloadHandler.ts}
Constructed Blob from ArrayBuffer (mediaBytes.buffer) instead of Uint8Array directly.
Website tests and setup
website/__tests__/**, website/vitest.config.ts, website/vitest.setup.ts, website/__tests__/setup/**, website/.gitignore
Added extensive unit/integration tests for API routes, hooks, components, pages; introduced URQL/Apollo/Wagmi mocks, test utils, Vitest config/setup, JUnit reporting, cache of results; ignored test-results.
Subsquid tests and setup
subsquid/package.json, subsquid/vitest.config.ts, subsquid/tests/**
Added Vitest config, test scripts/dev deps, mock fixtures, skipped unit/integration tests scaffolding for models and event processing.
Contracts: tests and coverage
contract/test/*.test.ts, contract/.solcover.js, contract/package.json, contract/.gitignore, contract/hardhat.config.base.ts
Removed two test suites; rewrote token tests focusing on ERC20 + permit; added solcover config, coverage scripts/JUnit reporter, test-results ignore, Mocha reporter config.
Config, workflows, and docs
.github/{workflows/*.yml,dependabot.yml,PULL_REQUEST_TEMPLATE.md}, website/next.config.mjs, website/package.json, website/README.md, website/lighthouserc.js, contract/README.md, README.md
Added CI (coverage, Lighthouse), Dependabot, PR template; removed Next experimental instrumentationHook; bumped packages (Next/React/TS, GraphQL tooling), scripts; switched docs/commands to npm; added Lighthouse config; badges in root README.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant NextServer as Next.js Server Page
  participant URQLSrv as createServerUrqlClient
  participant Subsquid as Subsquid GraphQL API

  User->>NextServer: Request /users/[address]
  NextServer->>NextServer: await params (Promise<{address}>)
  NextServer->>URQLSrv: create client
  NextServer->>Subsquid: query GET_USER_BY_ADDRESS
  Subsquid-->>NextServer: { data }
  NextServer-->>User: HTML (SSR) with data
Loading
sequenceDiagram
  autonumber
  actor Component
  participant URQL as urql useQuery
  participant Subsquid as Subsquid GraphQL API
  participant JobsHook as useJobsByIds

  Component->>URQL: useQuery(GET_USER_NOTIFICATIONS, vars)
  URQL->>Subsquid: GraphQL request
  Subsquid-->>URQL: { notifications }
  URQL-->>Component: result { data, fetching, error }
  Component->>JobsHook: derive jobIds, useJobsByIds(jobIds)
  JobsHook->>Subsquid: GET_JOBS_BY_IDS
  Subsquid-->>JobsHook: { jobs }
  JobsHook-->>Component: { data, loading, error }
  Component-->>Component: Map notifications + jobs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Poem

A nibble of code, a hop through the wire,
URQL burrows where Apollo would retire.
Tests sprout like clover, green and bright,
CI moonbeams measure the night.
Icons gleam, stars align—five in a row,
This rabbit approves—ship it, let’s go! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “Upgrade nextjs” references a real aspect of the changeset (the Next.js version bump and config update) but is overly narrow given the broad scope of dependency upgrades, GraphQL client migration, and extensive refactoring included in this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19e35aa and 6a6306b.

⛔ Files ignored due to path filters (2)
  • website/package-lock.json is excluded by !**/package-lock.json
  • website/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (11)
  • website/next.config.mjs (0 hunks)
  • website/package.json (1 hunks)
  • website/src/app/arbitrators/[address]/page.tsx (2 hunks)
  • website/src/app/jobs/[id]/JobActions/PostMessageButton.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobActions/UpdateButton.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobChat/JobChatStatus.tsx (0 hunks)
  • website/src/app/jobs/[id]/page.tsx (2 hunks)
  • website/src/app/post-job/PostJobPage.tsx (1 hunks)
  • website/src/app/users/[address]/page.tsx (2 hunks)
  • website/src/components/AddToHomescreen.tsx (0 hunks)
  • website/src/hooks/useWriteContractWithNotifications.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • website/src/app/jobs/[id]/JobChat/JobChatStatus.tsx
  • website/next.config.mjs
  • website/src/components/AddToHomescreen.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
website/src/app/users/[address]/page.tsx (1)
website/src/app/users/[address]/UserPageClient.tsx (1)
  • UserPageClient (56-389)
website/src/app/jobs/[id]/page.tsx (1)
website/src/app/jobs/[id]/JobPageClient.tsx (1)
  • JobPageClient (83-579)
website/src/app/arbitrators/[address]/page.tsx (1)
website/src/app/arbitrators/[address]/ArbitratorPageClient.tsx (1)
  • ArbitratorPageClient (67-467)
🔇 Additional comments (5)
website/src/app/post-job/PostJobPage.tsx (1)

384-384: LGTM! Type annotation correctly reflects React ref semantics.

The widened type React.RefObject<HTMLDivElement | null> properly aligns with React's ref behavior where current can be null before mounting. This matches the null check at line 459 and improves type safety.

website/src/app/jobs/[id]/JobActions/UpdateButton.tsx (1)

289-289: LGTM! Type annotation correctly reflects React ref semantics.

The widened type React.RefObject<HTMLDivElement | null> properly aligns with React's ref behavior where current can be null before mounting. This matches the null check at line 361 and improves type safety.

website/src/hooks/useWriteContractWithNotifications.ts (1)

102-106: LGTM! Explicit ref initialization improves clarity.

The explicit undefined initialization for these refs is clearer and more intentional than relying on implicit defaults. All three refs are safely used throughout the code with optional chaining (lines 237, 247) or null checks (line 125).

website/src/app/jobs/[id]/page.tsx (2)

101-107: LGTM! Correctly updated for Next.js 15.

The generateMetadata function properly awaits the params Promise before destructuring the id. This aligns with Next.js 15's change to async route parameters.


201-208: LGTM! Server component correctly migrated to async params.

The JobPage component properly awaits the params Promise and passes the unwrapped id string to JobPageClient, which expects a string parameter as confirmed by the relevant code snippets.

- Add GitHub Actions workflow for website testing with coverage reporting
- Add pull request template with comprehensive checklist
- Add Jest configuration and setup for frontend testing
- Add extensive test coverage for components, hooks, and API routes
- Add mock implementations for wagmi, Apollo, and contract dependencies
- Update README with testing instructions and coverage badge
- Add test utilities and mock data for consistent test execution
- Add GitHub Actions workflow for running contract tests with coverage
- Update EACCToken tests to use correct import paths and remove unused imports
- Remove obsolete EACCBar and MarketplaceV2 test files
- Fix publishMediaToIpfs function calls in utils tests
- Remove IPFS upload secret check from utils tests
Moved all test files to __tests__ directory and updated import paths accordingly. This change restructures the testing organization to be more consistent and maintainable.
- Configure Vitest for unit and integration testing with coverage support
- Add mock event data fixtures for job-related events and entities
- Create unit tests for data models, event types, and job event processing
- Add skipped integration tests for database operations with setup instructions
- Update package.json with test scripts and dev dependencies
This commit replaces Apollo Client with URQL across the application for several key reasons:
- Better integration with Next.js server components
- Automatic cache invalidation without manual resets
- Improved performance for server-side rendering
- Reduced bundle size by removing Apollo dependencies

The migration includes:
- Removed @apollo/client and related dependencies
- Added urql, wonka, and graphql-tag as dependencies
- Updated all GraphQL hooks and components to use URQL
- Rewrote server-side data fetching with createServerUrqlClient
- Updated testing utilities to mock URQL instead of Apollo
- Enhanced cache configuration with ssrExchange for better SSR support

Key benefits:
- Eliminates manual cache reset logic previously required with Apollo
- Server components now fetch data more efficiently
- Simplified testing setup with URQL's more straightforward mocking
- Better TypeScript support with automatic BigInt handling
Copy link

@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: 46

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
website/src/hooks/useSwResetMessage.tsx (1)

3-30: Verify URQL cache invalidation behavior
The client uses the default cacheExchange without external invalidation—ensure resets actually triggers query refetch (e.g., pass it as a variable/key) or invoke urqlClient.reexecuteQuery() in useSwResetMessage.

website/src/hooks/subsquid/useJobSearch.tsx (1)

88-101: Invalid GraphQL filter when userAddress is provided.

allowedWorkers_containsAny expects a list input, but we’re injecting a bare string literal. As soon as userAddress is defined the generated query is invalid (allowedWorkers_containsAny: "0x..."), so Subsquid rejects the request and the hook never resolves. Wrap the address in an array (e.g. ["${userAddress}"]) before interpolating the filter.

🧹 Nitpick comments (23)
subsquid/vitest.config.ts (1)

8-8: Consider including .spec.ts files in the test pattern.

The current pattern only matches *.test.ts files. For flexibility and consistency with common testing conventions, consider also matching *.spec.ts files.

Apply this diff to broaden the test file matching:

-    include: ['tests/**/*.test.ts'],
+    include: ['tests/**/*.{test,spec}.ts'],
subsquid/tests/integration/database.test.ts (1)

17-23: Consider a more idiomatic placeholder test.

The current placeholder test with expect(true).toBe(true) is functional but redundant. Consider one of these alternatives:

  1. Remove the assertion entirely (the test will pass by default)
  2. Use a more descriptive assertion that documents the intent

Apply this diff for option 1 (simplest):

   it('should have database integration tests when enabled', () => {
     // Placeholder test for when integration tests are enabled
     // See the comment block above for instructions on enabling these tests
-    expect(true).toBe(true);
   });

Or for option 2 (more descriptive):

   it('should have database integration tests when enabled', () => {
-    // Placeholder test for when integration tests are enabled
-    // See the comment block above for instructions on enabling these tests
-    expect(true).toBe(true);
+    // This is a placeholder. Remove .skip from describe.skip above and
+    // uncomment the scaffold code below to enable real integration tests
   });
subsquid/tests/unit/data-models.test.ts (2)

4-12: Clear explanation for skipped tests.

The comment appropriately explains why these tests are skipped and provides actionable alternatives (integration tests or factory functions). This is good documentation for future maintainers.

Consider adding a brief note about what specific setup is missing, to make it even more actionable:

  * Note: These tests are currently skipped because the TypeORM models
  * require reflect-metadata and specific TypeORM setup to instantiate.
+ * Specifically: import 'reflect-metadata' and a configured DataSource.
  * To test the models properly, you should:

16-39: Test structure is sound, assuming constructor signature matches.

The test correctly uses getAddress for checksummed addresses and covers key User properties. Assertions are appropriate for a basic model test.

The address_ property name (with trailing underscore) is unusual. Verify whether this matches the actual User entity schema. If the entity uses address (without underscore), update the test accordingly.

website/__tests__/lib/tokens.test.ts (1)

9-38: Consider parameterizing token-specific tests.

While the individual token tests (USDC, USDT, WETH, AIUS, EACC) are correct, they contain hardcoded expectations that could become brittle if token details change. Consider using a data-driven approach:

const expectedTokens = [
  { symbol: 'USDC', name: 'USD Coin', decimals: 6 },
  { symbol: 'USDT', name: 'USDT', decimals: 6 },
  { symbol: 'WETH', name: 'Wrapped Ether', decimals: 18 },
  // ... etc
];

it.each(expectedTokens)('should have $symbol token with correct properties', ({ symbol, name, decimals }) => {
  const token = tokens.find((t) => t.symbol === symbol);
  expect(token).toBeDefined();
  expect(token?.name).toBe(name);
  if (decimals !== undefined) {
    expect(token?.decimals).toBe(decimals);
  }
});

This would make the tests more maintainable and easier to update when tokens change.

website/__tests__/lib/utils.test.ts (1)

150-182: LGTM!

The isImageValid test suite correctly validates success, failure, and error scenarios with appropriate console.error mocking.

Optionally, verify the Sentry.captureException call in the error scenario:

  it('should return false on fetch error', async () => {
    (global.fetch as jest.Mock).mockRejectedValue(new Error('Network error'));
    const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
+   const sentrySpy = jest.spyOn(Sentry, 'captureException').mockImplementation();
    const result = await isImageValid('https://example.com/error.jpg');
    expect(result).toBe(false);
+   expect(sentrySpy).toHaveBeenCalledWith(expect.any(Error));
    consoleSpy.mockRestore();
+   sentrySpy.mockRestore();
  });
website/src/app/open-job-list/page.tsx (1)

8-9: LGTM! Dynamic rendering enforced for URQL compatibility.

The dynamic = 'force-dynamic' export correctly forces request-time rendering to avoid URQL prerendering issues. The comment clearly explains the rationale.

Consider investigating URQL's SSR configuration to enable static prerendering in the future. URQL supports SSR with proper setup (e.g., using ssrExchange and server-side data prefetching). This could improve performance by allowing static generation where appropriate.

subsquid/tests/unit/job-event-processing.test.ts (4)

24-33: Strengthen enum value assertions.

The tests only verify that enum properties exist but don't validate their actual values. Consider asserting the specific numeric values to catch accidental changes to the enum definitions.

Apply this diff to add value assertions:

   describe('JobEventType', () => {
     it('should have correct event type values', () => {
-      expect(JobEventType.Created).toBeDefined();
-      expect(JobEventType.Taken).toBeDefined();
-      expect(JobEventType.Paid).toBeDefined();
-      expect(JobEventType.Updated).toBeDefined();
-      expect(JobEventType.Signed).toBeDefined();
-      expect(JobEventType.Completed).toBeDefined();
+      expect(JobEventType.Created).toBe(0);
+      expect(JobEventType.Taken).toBe(1);
+      expect(JobEventType.Paid).toBe(2);
+      expect(JobEventType.Updated).toBe(3);
+      expect(JobEventType.Signed).toBe(4);
+      expect(JobEventType.Completed).toBe(5);
     });
   });

35-41: Strengthen state value assertions.

Similar to the JobEventType tests, these only check existence. Assert the specific numeric values (0, 1, 2) to ensure the enum contract is preserved.

Apply this diff:

   describe('JobState', () => {
     it('should have correct state values', () => {
-      expect(JobState.Open).toBeDefined();
-      expect(JobState.Taken).toBeDefined();
-      expect(JobState.Closed).toBeDefined();
+      expect(JobState.Open).toBe(0);
+      expect(JobState.Taken).toBe(1);
+      expect(JobState.Closed).toBe(2);
     });
   });

43-80: Add functional decoder tests.

The current tests only verify that decoder functions exist. The mock data from ../fixtures/mock-events is imported but never used. Consider adding tests that actually encode mock data and then decode it to verify round-trip correctness.

Example pattern for one decoder:

it('should correctly decode JobCreated event data', () => {
  // First encode the mock data (you'll need an encode function)
  const encoded = encodeJobCreatedEvent(mockJobCreatedEventData);
  
  // Then decode and verify
  const decoded = decodeJobCreatedEvent(encoded);
  expect(decoded.title).toBe(mockJobCreatedEventData.title);
  expect(decoded.contentHash).toBe(mockJobCreatedEventData.contentHash);
  expect(decoded.amount).toBe(mockJobCreatedEventData.amount);
  // ... verify all fields
});

111-117: Remove redundant state type test.

Lines 112-116 duplicate what's already tested in the "JobState" describe block (lines 35-41). This test validates that state values are numbers, which is already implicitly covered.

Consider removing this redundant test block:

-  describe('Job State Transitions', () => {
-    it('should validate job state values are numbers', () => {
-      expect(typeof JobState.Open).toBe('number');
-      expect(typeof JobState.Taken).toBe('number');
-      expect(typeof JobState.Closed).toBe('number');
-    });
-  });
website/__tests__/hooks/useDimensions.test.tsx (2)

22-35: Simplify ref mocking approach.

Directly assigning a partial HTMLDivElement object to ref.current works but is brittle. Consider using a more realistic test setup or document this as a unit-level mock pattern.


49-64: Add test for actual resize behavior.

The current test only verifies that addEventListener is called with 'resize' but doesn't test that the hook actually updates dimensions when a resize event fires. Consider adding a test that triggers a resize event and verifies the dimensions update.

Add a test like this:

it('should update dimensions on window resize', async () => {
  const { result, rerender } = renderHook(() => {
    const ref = useRef<HTMLDivElement>({
      offsetWidth: 100,
      offsetHeight: 200,
    } as HTMLDivElement);
    return { ref, dimensions: useDimensions(ref) };
  });

  expect(result.current.dimensions).toEqual({ width: 100, height: 200 });

  // Simulate element size change
  Object.assign(result.current.ref.current, {
    offsetWidth: 150,
    offsetHeight: 250,
  });

  // Trigger resize event
  act(() => {
    window.dispatchEvent(new Event('resize'));
  });

  await waitFor(() => {
    expect(result.current.dimensions).toEqual({ width: 150, height: 250 });
  });
});
website/__tests__/api/total_supply.test.ts (2)

34-42: Strengthen cache validation test.

Calling GET() twice in immediate succession doesn't effectively test the 24-hour cache behavior. The test only verifies that the mock returns consistent data, not that caching actually works.

Consider using Jest's fake timers to advance time and verify cache expiration:

it('should cache the result for 24 hours', async () => {
  jest.useFakeTimers();
  
  const response1 = await GET();
  const data1 = await response1.json();
  
  // Advance time by 23 hours - should still use cache
  jest.advanceTimersByTime(23 * 60 * 60 * 1000);
  
  const response2 = await GET();
  const data2 = await response2.json();
  expect(data2.totalSupply).toBe(data1.totalSupply);
  
  // Advance past 24 hours - should fetch fresh data
  jest.advanceTimersByTime(2 * 60 * 60 * 1000);
  
  const response3 = await GET();
  const data3 = await response3.json();
  // Verify fresh fetch (may need to change mock to return different value)
  
  jest.useRealTimers();
});

44-54: Verify error handling behavior.

The error handling test mocks a rejection but only verifies that a response exists. It should verify that the API returns an appropriate error response or cached data when the RPC call fails.

Enhance the test to verify the actual error handling:

   it('should handle RPC errors', async () => {
     const { Contract } = require('ethers');
     Contract.mockImplementationOnce(() => ({
       totalSupply: jest.fn().mockRejectedValue(new Error('Network error')),
     }));

     const response = await GET();
+    const data = await response.json();

-    // Should still return a response (from cache or error handling)
-    expect(response).toBeDefined();
+    // Should return error response or cached data
+    expect(response.status).toBeGreaterThanOrEqual(200);
+    expect(data).toHaveProperty('totalSupply');
+    // OR verify error response structure if that's the expected behavior
   });
website/__tests__/api/circulating_supply.test.ts (1)

56-67: Strengthen error test to verify error handling behavior.

The error test only checks that response is defined, but doesn't verify how the error was handled (e.g., returning cached data, specific status code, or error payload). The comment suggests "Should return cached data or fallback" but this isn't asserted.

Consider enhancing the test to verify the actual error handling behavior:

 it('should handle errors gracefully', async () => {
   // Mock contract error
   const { Contract } = require('ethers');
   Contract.mockImplementationOnce(() => ({
     totalSupply: jest.fn().mockRejectedValue(new Error('RPC Error')),
   }));

   const response = await GET();
+  const data = await response.json();

-  // Should return cached data or fallback
-  expect(response).toBeDefined();
+  // Should return cached data or a valid fallback value
+  expect(response).toBeDefined();
+  expect(response.status).toBe(200); // or appropriate error status
+  expect(data).toHaveProperty('circulatingSupply');
+  expect(typeof data.circulatingSupply).toBe('string');
 });

This ensures the error path returns a valid response structure and doesn't just pass by accident.

website/src/hooks/subsquid/useJobs.tsx (1)

37-48: Simplify useMemo dependencies.

The dependency array includes [fake, offset, limit, maxTimestamp, minTimestamp, result] (line 46), but offset, limit, maxTimestamp, and minTimestamp are already query variables that affect result. Including them separately is redundant and may cause unnecessary memoization.

-  }, [fake, offset, limit, maxTimestamp, minTimestamp, result]);
+  }, [fake, result]);

The result object already captures changes to the query variables, and fake controls the conditional logic.

website/src/hooks/subsquid/useUsers.tsx (1)

19-26: Simplify useMemo dependencies.

The dependency array includes [offset, limit, result] (line 25), but offset and limit are query variables that already affect result. Including them separately is redundant.

-    [offset, limit, result]
+    [result]
website/__tests__/hooks/subsquid/useCreatorDisputedJobs.test.tsx (1)

1-2: Consider migrating to URQL mocks for consistency.

This test uses Apollo's MockedProvider, but the PR migrates the codebase from Apollo to URQL. For consistency with the broader migration, consider updating this test to use URQL mocks instead.

Based on the URQL migration patterns in the PR, you can use URQL's testing utilities. The test utilities are available at website/__tests__/setup/mocks/urql.ts and website/__tests__/setup/test-utils.tsx.

website/src/hooks/subsquid/useMarketplace.tsx (1)

6-9: Consider removing the empty variables object.

The query doesn't use any variables, so passing an empty object is unnecessary. While harmless, omitting it makes the code cleaner.

Apply this diff:

   const [result] = useQuery({
     query: GET_MARKETPLACES,
-    variables: {},
   });
website/__tests__/hooks/subsquid/useUsers.test.tsx (1)

1-2: Migrate to URQL mocks for consistency.

This test uses Apollo's MockedProvider, but the PR migrates the entire codebase from Apollo to URQL (see the URQL client setup in website/src/lib/urql-client.ts and website/src/lib/urql-server.ts). For consistency with the broader migration, update this test to use URQL testing utilities.

The codebase provides URQL test utilities at website/__tests__/setup/mocks/urql.ts and website/__tests__/setup/test-utils.tsx. Consider refactoring this test to use those utilities instead of Apollo's MockedProvider.

website/src/app/users/[address]/page.tsx (2)

83-88: Consider checking URQL's result.error for robust error handling.

The URQL query pattern is correct, but the result object can contain an error property when the query fails. While the current code safely handles undefined data with optional chaining, explicitly checking for errors would provide better observability.

Consider this pattern for more explicit error handling:

 const client = createServerUrqlClient();

 const result = await client
   .query(GET_USER_QUERY, { address: checksummedAddress })
   .toPromise();
+
+if (result.error) {
+  console.error('GraphQL query error:', result.error);
+  return null;
+}
+
 const data = result.data;

This change makes error paths more explicit and improves debugging by surfacing GraphQL-specific errors separately from network/runtime exceptions.


110-115: Consider checking URQL's result.error (consistent with line 85-88).

Same pattern as getCachedUserData: explicitly checking result.error would improve error handling and observability.

Apply the same pattern:

 const client = createServerUrqlClient();

 const result = await client
   .query(GET_USER_REVIEWS_QUERY, { address: checksummedAddress })
   .toPromise();
+
+if (result.error) {
+  console.error('GraphQL query error:', result.error);
+  return [];
+}
+
 const data = result.data;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6a6306b and 08ead0d.

⛔ Files ignored due to path filters (4)
  • subsquid/package-lock.json is excluded by !**/package-lock.json
  • website/package-lock.json is excluded by !**/package-lock.json
  • website/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (103)
  • .github/PULL_REQUEST_TEMPLATE.md (1 hunks)
  • .github/workflows/test-contract.yml (1 hunks)
  • .github/workflows/test-website.yml (1 hunks)
  • contract/test/eaccbar.test.ts (0 hunks)
  • contract/test/eacctoken.test.ts (1 hunks)
  • contract/test/marketplacev2.test.ts (0 hunks)
  • contract/test/utils.test.ts (1 hunks)
  • subsquid/package.json (2 hunks)
  • subsquid/tests/fixtures/mock-events.ts (1 hunks)
  • subsquid/tests/integration/database.test.ts (1 hunks)
  • subsquid/tests/unit/data-models.test.ts (1 hunks)
  • subsquid/tests/unit/event-types.test.ts (1 hunks)
  • subsquid/tests/unit/job-event-processing.test.ts (1 hunks)
  • subsquid/vitest.config.ts (1 hunks)
  • website/README.md (2 hunks)
  • website/__tests__/api/circulating_supply.test.ts (1 hunks)
  • website/__tests__/api/market_cap.test.ts (1 hunks)
  • website/__tests__/api/total_supply.test.ts (1 hunks)
  • website/__tests__/components/Button.test.tsx (1 hunks)
  • website/__tests__/components/Input.test.tsx (1 hunks)
  • website/__tests__/components/JobsList.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useArbitrator.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useArbitrators.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorCompletedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorDisputedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorOpenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorTakenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJob.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobEvents.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobSearch.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobsByIds.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useMarketplace.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useReviews.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useSquidStatus.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUser.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUserNotifications.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUsers.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerApplications.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerCompletedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerDisputedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerTakenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/useConfig.test.ts (1 hunks)
  • website/__tests__/hooks/useDimensions.test.tsx (1 hunks)
  • website/__tests__/hooks/useToast.test.ts (1 hunks)
  • website/__tests__/integration/job-creation-flow.test.tsx (1 hunks)
  • website/__tests__/lib/tokens.test.ts (1 hunks)
  • website/__tests__/lib/utils.test.ts (1 hunks)
  • website/__tests__/pages/AcceptButton.test.tsx (1 hunks)
  • website/__tests__/pages/ConnectWallet.test.tsx (1 hunks)
  • website/__tests__/pages/DeliverResultButton.test.tsx (1 hunks)
  • website/__tests__/pages/PostJobPage.test.tsx (1 hunks)
  • website/__tests__/pages/TakeJobButton.test.tsx (1 hunks)
  • website/__tests__/setup/mocks/apollo.ts (1 hunks)
  • website/__tests__/setup/mocks/contracts.ts (1 hunks)
  • website/__tests__/setup/mocks/urql.ts (1 hunks)
  • website/__tests__/setup/mocks/wagmi.ts (1 hunks)
  • website/__tests__/setup/test-utils.tsx (1 hunks)
  • website/jest.config.ts (1 hunks)
  • website/jest.setup.ts (1 hunks)
  • website/package.json (2 hunks)
  • website/src/app/arbitrators/[address]/page.tsx (4 hunks)
  • website/src/app/arbitrators/page.tsx (2 hunks)
  • website/src/app/jobs/[id]/page.tsx (4 hunks)
  • website/src/app/open-job-list/page.tsx (1 hunks)
  • website/src/app/post-job/page.tsx (1 hunks)
  • website/src/app/providers.tsx (2 hunks)
  • website/src/app/users/[address]/page.tsx (5 hunks)
  • website/src/app/users/page.tsx (2 hunks)
  • website/src/components/Dashboard/Navbar/NotificationsButton.tsx (1 hunks)
  • website/src/hooks/subsquid/queries.ts (1 hunks)
  • website/src/hooks/subsquid/useArbitrator.tsx (2 hunks)
  • website/src/hooks/subsquid/useArbitratorPublicKeys.tsx (1 hunks)
  • website/src/hooks/subsquid/useArbitrators.tsx (1 hunks)
  • website/src/hooks/subsquid/useArbitratorsByAddresses.tsx (2 hunks)
  • website/src/hooks/subsquid/useCreatorClosedJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useCreatorCompletedJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useCreatorDisputedJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useCreatorOpenJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useCreatorTakenJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useJob.tsx (1 hunks)
  • website/src/hooks/subsquid/useJobEvents.tsx (1 hunks)
  • website/src/hooks/subsquid/useJobSearch.tsx (3 hunks)
  • website/src/hooks/subsquid/useJobs.tsx (2 hunks)
  • website/src/hooks/subsquid/useJobsByIds.tsx (1 hunks)
  • website/src/hooks/subsquid/useMarketplace.tsx (1 hunks)
  • website/src/hooks/subsquid/useReviews.tsx (3 hunks)
  • website/src/hooks/subsquid/useSquidStatus.tsx (1 hunks)
  • website/src/hooks/subsquid/useUser.tsx (2 hunks)
  • website/src/hooks/subsquid/useUserJobNotifications.tsx (4 hunks)
  • website/src/hooks/subsquid/useUserNotifications.tsx (4 hunks)
  • website/src/hooks/subsquid/useUsers.tsx (2 hunks)
  • website/src/hooks/subsquid/useUsersByAddresses.tsx (2 hunks)
  • website/src/hooks/subsquid/useWorkerApplications.tsx (1 hunks)
  • website/src/hooks/subsquid/useWorkerCompletedJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useWorkerDisputedJobs.tsx (1 hunks)
  • website/src/hooks/subsquid/useWorkerTakenJobs.tsx (1 hunks)
  • website/src/hooks/useSwResetMessage.tsx (2 hunks)
  • website/src/hooks/useWriteContractWithNotifications.ts (3 hunks)
  • website/src/lib/urql-client.ts (1 hunks)
  • website/src/lib/urql-server.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • contract/test/eaccbar.test.ts
  • contract/test/marketplacev2.test.ts
🧰 Additional context used
🧬 Code graph analysis (72)
website/__tests__/hooks/subsquid/useWorkerApplications.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_APPLICATIONS (192-205)
website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS_BY_ADDRESSES (108-114)
website/src/hooks/subsquid/useUsersByAddresses.tsx (1)
  • useUsersByAddresses (13-47)
website/__tests__/hooks/subsquid/useWorkerDisputedJobs.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_DISPUTED_JOBS (223-229)
website/__tests__/hooks/subsquid/useArbitrator.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockArbitrator (38-45)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATOR_BY_ADDRESS (35-41)
website/src/hooks/subsquid/useArbitrator.tsx (1)
  • useArbitrator (11-38)
website/__tests__/hooks/subsquid/useUser.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USER_BY_ADDRESS (100-106)
website/src/hooks/subsquid/useUser.tsx (1)
  • useUser (22-46)
website/src/hooks/subsquid/useCreatorTakenJobs.tsx (6)
website/src/hooks/subsquid/useWorkerApplications.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerCompletedJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_TAKEN_JOBS (140-146)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/hooks/subsquid/useArbitratorPublicKeys.tsx (2)
website/src/hooks/subsquid/useArbitratorsByAddresses.tsx (1)
  • useArbitratorsByAddresses (6-38)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATORS_BY_ADDRESSES (43-49)
website/__tests__/hooks/subsquid/useWorkerCompletedJobs.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_COMPLETED_JOBS (215-221)
website/src/hooks/useSwResetMessage.tsx (2)
contract/src/interfaces.ts (1)
  • JobEvent (44-48)
website/src/lib/urql-client.ts (1)
  • urqlClient (6-17)
website/src/hooks/subsquid/useCreatorDisputedJobs.tsx (4)
website/src/hooks/subsquid/useWorkerDisputedJobs.tsx (1)
  • useCreatorDisputedJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_DISPUTED_JOBS (156-162)
contract/src/interfaces.ts (1)
  • Job (33-40)
subsquid/tests/unit/job-event-processing.test.ts (2)
contract/src/utils/decodeEvents.ts (7)
  • decodeJobCreatedEvent (6-22)
  • decodeJobUpdatedEvent (24-38)
  • decodeJobSignedEvent (40-46)
  • decodeJobRatedEvent (48-55)
  • decodeJobDisputedEvent (57-66)
  • decodeJobArbitratedEvent (88-100)
  • decodeJobMessageEvent (102-109)
subsquid/tests/fixtures/mock-events.ts (3)
  • mockJobCreatedEventData (3-14)
  • mockJobRatedEventData (30-33)
  • mockJobArbitratedEventData (39-43)
website/src/hooks/subsquid/useWorkerApplications.tsx (6)
website/src/hooks/subsquid/useCreatorTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerCompletedJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_APPLICATIONS (192-205)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/app/open-job-list/page.tsx (1)
website/src/app/post-job/page.tsx (1)
  • dynamic (6-6)
website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_CLOSED_JOBS (164-170)
website/src/hooks/subsquid/useCreatorClosedJobs.tsx (1)
  • useCreatorClosedJobs (7-24)
website/src/hooks/subsquid/useArbitrators.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATORS (27-33)
contract/src/interfaces.ts (1)
  • Arbitrator (17-17)
website/__tests__/hooks/subsquid/useSquidStatus.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_SQUID_STATUS (19-25)
website/src/hooks/subsquid/useSquidStatus.tsx (1)
  • useSquidStatus (5-21)
website/src/hooks/subsquid/useMarketplace.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_MARKETPLACES (11-17)
website/__tests__/hooks/subsquid/useCreatorTakenJobs.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_TAKEN_JOBS (140-146)
website/src/app/users/page.tsx (1)
website/src/lib/urql-server.ts (1)
  • createServerUrqlClient (4-14)
website/src/hooks/subsquid/useUserJobNotifications.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USER_JOB_NOTIFICATIONS (287-308)
website/src/service/Interfaces.ts (1)
  • Notification (29-36)
website/src/hooks/useWriteContractWithNotifications.ts (2)
website/src/lib/urql-client.ts (1)
  • urqlClient (6-17)
website/src/hooks/useToast.ts (1)
  • useToast (3-35)
website/__tests__/pages/AcceptButton.test.tsx (1)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/useJobs.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOBS (76-82)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/components/Dashboard/Navbar/NotificationsButton.tsx (1)
website/src/hooks/subsquid/useUserNotifications.tsx (1)
  • useUserNotifications (29-128)
website/__tests__/hooks/subsquid/useArbitrators.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATORS (27-33)
website/src/hooks/subsquid/useArbitrators.tsx (1)
  • useArbitrators (6-20)
website/__tests__/hooks/useToast.test.ts (1)
website/src/hooks/useToast.ts (1)
  • useToast (3-35)
website/__tests__/hooks/subsquid/useUserNotifications.test.tsx (2)
website/src/hooks/subsquid/queries.ts (2)
  • GET_USER_NOTIFICATIONS (231-251)
  • GET_JOBS_BY_IDS (68-74)
website/src/hooks/subsquid/useUserNotifications.tsx (1)
  • useUserNotifications (29-128)
website/src/hooks/subsquid/useJob.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_BY_ID (60-66)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/__tests__/lib/utils.test.ts (1)
website/src/lib/utils.ts (9)
  • cn (7-9)
  • formatDate (10-17)
  • absoluteUrl (18-20)
  • EventTextMap (21-90)
  • isImageValid (92-102)
  • shortenText (104-124)
  • convertToSeconds (126-143)
  • getUnitAndValueFromSeconds (145-171)
  • formatTimeLeft (182-191)
website/__tests__/setup/mocks/apollo.ts (1)
website/src/hooks/subsquid/queries.ts (2)
  • GET_JOBS (76-82)
  • GET_USERS (92-98)
website/__tests__/hooks/subsquid/useCreatorCompletedJobs.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_COMPLETED_JOBS (148-154)
website/src/hooks/subsquid/useCreatorCompletedJobs.tsx (1)
  • useCreatorCompletedJobs (7-24)
website/__tests__/hooks/subsquid/useJobEvents.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_EVENTS (124-130)
website/src/hooks/subsquid/useJobEvents.tsx (1)
  • useJobEvents (6-20)
website/src/hooks/subsquid/useArbitrator.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATOR_BY_ADDRESS (35-41)
website/__tests__/components/JobsList.test.tsx (2)
website/src/hooks/subsquid/useJobs.tsx (1)
  • useJobs (23-49)
website/src/components/Dashboard/JobsList/JobsList.tsx (1)
  • JobsList (8-14)
website/__tests__/hooks/subsquid/useUsers.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS (92-98)
website/src/hooks/subsquid/useUsers.tsx (1)
  • useUsers (13-27)
website/src/hooks/subsquid/useCreatorOpenJobs.tsx (3)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_OPEN_JOBS (132-138)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/__tests__/hooks/subsquid/useCreatorOpenJobs.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_OPEN_JOBS (132-138)
website/src/hooks/subsquid/useCreatorOpenJobs.tsx (1)
  • useCreatorOpenJobs (7-24)
website/src/app/jobs/[id]/page.tsx (3)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/lib/urql-server.ts (1)
  • createServerUrqlClient (4-14)
website/src/app/jobs/[id]/JobPageClient.tsx (1)
  • JobPageClient (83-579)
website/__tests__/hooks/subsquid/useJob.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_BY_ID (60-66)
website/src/hooks/subsquid/useJob.tsx (1)
  • useJob (6-20)
contract/test/utils.test.ts (1)
contract/src/utils/encryption.ts (1)
  • publishMediaToIpfs (71-88)
website/src/hooks/subsquid/useWorkerDisputedJobs.tsx (4)
website/src/hooks/subsquid/useCreatorDisputedJobs.tsx (1)
  • useCreatorDisputedJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_DISPUTED_JOBS (223-229)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/app/post-job/page.tsx (1)
website/src/app/open-job-list/page.tsx (1)
  • dynamic (9-9)
website/src/hooks/subsquid/useReviews.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_REVIEWS (116-122)
website/src/hooks/subsquid/useUsersByAddresses.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS_BY_ADDRESSES (108-114)
website/src/hooks/subsquid/useUser.tsx (1)
  • ExtendedUser (7-20)
website/src/hooks/subsquid/useSquidStatus.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_SQUID_STATUS (19-25)
website/__tests__/hooks/subsquid/useJobSearch.test.tsx (3)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_SEARCH (172-190)
website/src/hooks/subsquid/useJobSearch.tsx (1)
  • useJobSearch (10-130)
website/src/hooks/subsquid/useWorkerTakenJobs.tsx (6)
website/src/hooks/subsquid/useCreatorTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerApplications.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerCompletedJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_TAKEN_JOBS (207-213)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/app/arbitrators/[address]/page.tsx (2)
contract/src/interfaces.ts (1)
  • Arbitrator (17-17)
website/src/lib/urql-server.ts (1)
  • createServerUrqlClient (4-14)
subsquid/tests/unit/data-models.test.ts (2)
contract/src/interfaces.ts (4)
  • User (18-18)
  • Arbitrator (17-17)
  • Job (33-40)
  • Review (20-20)
subsquid/src/abi/MarketplaceDataV1.ts (1)
  • marketplace (136-138)
website/src/hooks/subsquid/useJobEvents.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_EVENTS (124-130)
contract/src/interfaces.ts (1)
  • JobEvent (44-48)
website/src/hooks/subsquid/useCreatorCompletedJobs.tsx (3)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_COMPLETED_JOBS (148-154)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/__tests__/components/Input.test.tsx (1)
website/src/components/Input.tsx (1)
  • Input (11-89)
website/src/hooks/subsquid/useUserNotifications.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USER_NOTIFICATIONS (231-251)
website/__tests__/hooks/subsquid/useJobsByIds.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOBS_BY_IDS (68-74)
website/src/hooks/subsquid/useJobsByIds.tsx (1)
  • useJobsByIds (6-21)
website/__tests__/hooks/subsquid/useCreatorDisputedJobs.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_DISPUTED_JOBS (156-162)
website/src/app/arbitrators/page.tsx (1)
website/src/lib/urql-server.ts (1)
  • createServerUrqlClient (4-14)
website/src/hooks/subsquid/useUser.tsx (1)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USER_BY_ADDRESS (100-106)
website/__tests__/hooks/subsquid/useMarketplace.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_MARKETPLACES (11-17)
website/src/hooks/subsquid/useMarketplace.tsx (1)
  • useMarketplace (5-19)
website/__tests__/hooks/useConfig.test.ts (1)
website/src/hooks/useConfig.ts (1)
  • useConfig (5-19)
website/__tests__/hooks/subsquid/useWorkerTakenJobs.test.tsx (2)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_TAKEN_JOBS (207-213)
website/src/app/providers.tsx (1)
website/src/lib/urql-client.ts (1)
  • urqlClient (6-17)
website/__tests__/setup/test-utils.tsx (1)
website/src/lib/urql-client.ts (1)
  • urqlClient (6-17)
website/src/hooks/subsquid/useWorkerCompletedJobs.tsx (6)
website/src/hooks/subsquid/useCreatorTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerApplications.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/hooks/subsquid/useWorkerTakenJobs.tsx (1)
  • useCreatorTakenJobs (7-24)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_COMPLETED_JOBS (215-221)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/jest.setup.ts (1)
website/__tests__/setup/mocks/contracts.ts (1)
  • mockConfig (9-14)
website/__tests__/hooks/subsquid/useReviews.test.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_REVIEWS (116-122)
website/src/hooks/subsquid/useReviews.tsx (1)
  • useReviews (12-74)
website/__tests__/hooks/subsquid/useJobs.test.tsx (2)
website/__tests__/setup/mocks/urql.ts (1)
  • createMockClient (6-24)
website/src/hooks/subsquid/useJobs.tsx (1)
  • useJobs (23-49)
website/src/app/users/[address]/page.tsx (2)
website/src/lib/urql-server.ts (1)
  • createServerUrqlClient (4-14)
website/src/app/users/[address]/UserPageClient.tsx (1)
  • UserPageClient (56-389)
website/src/hooks/subsquid/useCreatorClosedJobs.tsx (3)
website/src/service/Interfaces.ts (1)
  • OrderByType (38-79)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_CLOSED_JOBS (164-170)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/hooks/subsquid/useJobsByIds.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOBS_BY_IDS (68-74)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/hooks/subsquid/useJobSearch.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_SEARCH (172-190)
contract/src/interfaces.ts (1)
  • Job (33-40)
website/src/hooks/subsquid/useUsers.tsx (3)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS (92-98)
website/src/hooks/subsquid/useUser.tsx (1)
  • ExtendedUser (7-20)
website/src/hooks/subsquid/useUsersByAddresses.tsx (1)
  • ExtendedUser (7-11)
website/src/hooks/subsquid/useArbitratorsByAddresses.tsx (2)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATORS_BY_ADDRESSES (43-49)
contract/src/interfaces.ts (1)
  • Arbitrator (17-17)
🪛 Biome (2.1.2)
website/__tests__/setup/mocks/urql.ts

[error] 31-31: expected > but instead found value

Remove value

(parse)


[error] 31-31: Invalid assignment to <Provider value

This expression cannot be assigned to

(parse)


[error] 31-31: unterminated regex literal

...but the line ends here

a regex literal starts there...

(parse)

Comment on lines 44 to 52
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./contract/coverage/lcov.info
flag-name: contract
parallel: false
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Coveralls upload breaks on forked PRs

Forked pull requests won’t receive COVERALLS_REPO_TOKEN, so this step fails and the whole workflow turns red for external contributors. Please guard the Coveralls upload so it only runs when the secret is present (or switch to the Coveralls GitHub App flow).

Consider:

       - name: Upload coverage to Coveralls
-        uses: coverallsapp/github-action@v2
+        if: ${{ secrets.COVERALLS_REPO_TOKEN != '' }}
+        uses: coverallsapp/github-action@v2
         with:
           github-token: ${{ secrets.GITHUB_TOKEN }}
           path-to-lcov: ./contract/coverage/lcov.info
           flag-name: contract
           parallel: false
         env:
           COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
🤖 Prompt for AI Agents
In .github/workflows/test-contract.yml around lines 44 to 52, the Coveralls
upload step runs on forked PRs without the COVERALLS_REPO_TOKEN and fails; guard
the step so it only runs when the secret is present. Add an if condition to the
upload step that checks the secret (for example using GitHub Actions expression
checking secrets.COVERALLS_REPO_TOKEN is non-empty) or switch to the Coveralls
GitHub App flow; ensure the step is skipped when the secret is absent to avoid
failing workflows for external contributors.

Comment on lines +24 to +54
/*
* Uncomment the code below and import the required models when ready to enable integration tests
*
* import { DataSource } from 'typeorm';
* import { ZeroAddress, getAddress } from 'ethers';
* import { User, Arbitrator, Job, JobRoles, JobTimes, Marketplace } from '../../src/model';
*
* let dataSource: DataSource;
*
* beforeAll(async () => {
* dataSource = new DataSource({
* type: 'postgres',
* host: process.env.DB_HOST || 'localhost',
* port: parseInt(process.env.DB_PORT || '5432'),
* database: process.env.DB_NAME || 'squid',
* username: process.env.DB_USER || 'postgres',
* password: process.env.DB_PASS || 'postgres',
* entities: [User, Arbitrator, Job, Marketplace],
* synchronize: false,
* });
* await dataSource.initialize();
* });
*
* afterAll(async () => {
* if (dataSource?.isInitialized) {
* await dataSource.destroy();
* }
* });
*
* // Add your integration tests here
*/
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Address inconsistencies in the commented scaffold.

The commented scaffold has a few issues to fix before enabling:

  1. Missing entities in DataSource configuration: Lines 29 imports JobRoles and JobTimes, but line 41 only includes [User, Arbitrator, Job, Marketplace]. Either remove the unused imports or add these entities to the array.

  2. Missing vitest lifecycle imports: The scaffold uses beforeAll and afterAll (lines 33, 47) but these are not in the import list at line 27. These should be imported from 'vitest'.

  3. Port parsing could be more robust: Line 37 uses parseInt without a radix, and could fail silently on invalid input (though the fallback '5432' provides safety).

Apply this diff to fix the issues:

  * Uncomment the code below and import the required models when ready to enable integration tests
  *
+ * import { beforeAll, afterAll } from 'vitest';
  * import { DataSource } from 'typeorm';
  * import { ZeroAddress, getAddress } from 'ethers';
- * import { User, Arbitrator, Job, JobRoles, JobTimes, Marketplace } from '../../src/model';
+ * import { User, Arbitrator, Job, Marketplace } from '../../src/model';
  *
  * let dataSource: DataSource;
  *
  * beforeAll(async () => {
  *   dataSource = new DataSource({
  *     type: 'postgres',
  *     host: process.env.DB_HOST || 'localhost',
-*     port: parseInt(process.env.DB_PORT || '5432'),
+*     port: parseInt(process.env.DB_PORT || '5432', 10),
  *     database: process.env.DB_NAME || 'squid',
  *     username: process.env.DB_USER || 'postgres',
  *     password: process.env.DB_PASS || 'postgres',
  *     entities: [User, Arbitrator, Job, Marketplace],
  *     synchronize: false,
  *   });
  *   await dataSource.initialize();
  * });

Note: If JobRoles and JobTimes are TypeORM entities that should be included in the DataSource, add them back to the entities array instead of removing them from the imports.

📝 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
/*
* Uncomment the code below and import the required models when ready to enable integration tests
*
* import { DataSource } from 'typeorm';
* import { ZeroAddress, getAddress } from 'ethers';
* import { User, Arbitrator, Job, JobRoles, JobTimes, Marketplace } from '../../src/model';
*
* let dataSource: DataSource;
*
* beforeAll(async () => {
* dataSource = new DataSource({
* type: 'postgres',
* host: process.env.DB_HOST || 'localhost',
* port: parseInt(process.env.DB_PORT || '5432'),
* database: process.env.DB_NAME || 'squid',
* username: process.env.DB_USER || 'postgres',
* password: process.env.DB_PASS || 'postgres',
* entities: [User, Arbitrator, Job, Marketplace],
* synchronize: false,
* });
* await dataSource.initialize();
* });
*
* afterAll(async () => {
* if (dataSource?.isInitialized) {
* await dataSource.destroy();
* }
* });
*
* // Add your integration tests here
*/
/*
* Uncomment the code below and import the required models when ready to enable integration tests
*
* import { beforeAll, afterAll } from 'vitest';
* import { DataSource } from 'typeorm';
* import { ZeroAddress, getAddress } from 'ethers';
* import { User, Arbitrator, Job, Marketplace } from '../../src/model';
*
* let dataSource: DataSource;
*
* beforeAll(async () => {
* dataSource = new DataSource({
* type: 'postgres',
* host: process.env.DB_HOST || 'localhost',
* port: parseInt(process.env.DB_PORT || '5432', 10),
* database: process.env.DB_NAME || 'squid',
* username: process.env.DB_USER || 'postgres',
* password: process.env.DB_PASS || 'postgres',
* entities: [User, Arbitrator, Job, Marketplace],
* synchronize: false,
* });
* await dataSource.initialize();
* });
*
* afterAll(async () => {
* if (dataSource?.isInitialized) {
* await dataSource.destroy();
* }
* });
*
* // Add your integration tests here
*/
🤖 Prompt for AI Agents
In subsquid/tests/integration/database.test.ts around lines 24 to 54, the
commented scaffold has inconsistent imports and minor robustness issues: update
the import block to include vitest lifecycle functions (import beforeAll and
afterAll from 'vitest'), make the DataSource entities array match the imported
entities (add JobRoles and JobTimes to entities if they are TypeORM entities,
otherwise remove their imports), and make port parsing explicit by using
parseInt(process.env.DB_PORT || '5432', 10). Ensure the rest of the scaffold
remains commented until ready to enable.

Comment on lines +1 to +3
import { describe, it, expect } from 'vitest';
import { ZeroAddress, ZeroHash, getAddress } from 'ethers';

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Missing imports for all model classes.

The test file references User, Arbitrator, Job, Review, Marketplace, JobRoles, and JobTimes throughout but never imports them. If these tests are unskipped, they will fail immediately with "ReferenceError: User is not defined" (and similar for other models).

Add the missing imports at the top of the file. Based on the project structure, you likely need:

 import { describe, it, expect } from 'vitest';
 import { ZeroAddress, ZeroHash, getAddress } from 'ethers';
+import { User } from '../path/to/User';
+import { Arbitrator } from '../path/to/Arbitrator';
+import { Job } from '../path/to/Job';
+import { JobRoles } from '../path/to/JobRoles';
+import { JobTimes } from '../path/to/JobTimes';
+import { Review } from '../path/to/Review';
+import { Marketplace } from '../path/to/Marketplace';

Run the following script to locate the model class definitions:


🏁 Script executed:

#!/bin/bash
# Find TypeORM entity definitions
rg -n --type=ts -C3 '@Entity.*User|@Entity.*Arbitrator|@Entity.*Job|@Entity.*Review|@Entity.*Marketplace' subsquid/

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for all TypeORM entity definitions across the repo
rg -n --type=ts '@Entity' -C3 .

Length of output: 4972


🏁 Script executed:

#!/bin/bash
# Locate JobRoles and JobTimes class definitions
rg -n --type=ts 'export class JobRoles' -C3 .
rg -n --type=ts 'export class JobTimes' -C3 .
# Search by filename
fd JobRoles
fd JobTimes

Length of output: 1142


Add missing model imports

The test references User, Review, Job, Marketplace, Arbitrator, JobRoles, and JobTimes but doesn’t import them; unskipping will cause ReferenceErrors.

 import { describe, it, expect } from 'vitest';
 import { ZeroAddress, ZeroHash, getAddress } from 'ethers';
+import { User } from '../../src/model/generated/user.model';
+import { Review } from '../../src/model/generated/review.model';
+import { Job } from '../../src/model/generated/job.model';
+import { Marketplace } from '../../src/model/generated/marketplace.model';
+import { Arbitrator } from '../../src/model/generated/arbitrator.model';
+import { JobRoles } from '../../src/model/generated/_jobRoles';
+import { JobTimes } from '../../src/model/generated/_jobTimes';
📝 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
import { describe, it, expect } from 'vitest';
import { ZeroAddress, ZeroHash, getAddress } from 'ethers';
import { describe, it, expect } from 'vitest';
import { ZeroAddress, ZeroHash, getAddress } from 'ethers';
import { User } from '../../src/model/generated/user.model';
import { Review } from '../../src/model/generated/review.model';
import { Job } from '../../src/model/generated/job.model';
import { Marketplace } from '../../src/model/generated/marketplace.model';
import { Arbitrator } from '../../src/model/generated/arbitrator.model';
import { JobRoles } from '../../src/model/generated/_jobRoles';
import { JobTimes } from '../../src/model/generated/_jobTimes';
🤖 Prompt for AI Agents
In subsquid/tests/unit/data-models.test.ts lines 1-3, the test file imports
vitest and ethers but is missing named imports for the data models used (User,
Review, Job, Marketplace, Arbitrator, JobRoles, JobTimes); add named imports for
those symbols from the module that defines your ORM/data models (e.g., the
project file that exports them — adjust path accordingly) by adding a single
import statement at the top like: import { User, Review, Job, Marketplace,
Arbitrator, JobRoles, JobTimes } from '<correct-models-module-path>'; this will
prevent ReferenceErrors when unskipping tests.

Comment on lines 15 to +25
useEffect(() => {
if (data) {
if (result.data) {
const results: Record<string, string> = {};
for (const arbitrator of data.arbitrators) {
for (const arbitrator of result.data.arbitrators) {
resultMap[arbitrator.address_] = arbitrator.publicKey;
}

setResultMap((prev) => ({ ...prev, ...results }));
}
}, [data]);
}, [result.data]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Variable assignment bug in effect.

Line 20 assigns to resultMap instead of the local results object:

resultMap[arbitrator.address_] = arbitrator.publicKey;

This means the local results object remains empty and setResultMap on line 23 receives an empty object merged with previous state. New arbitrator data won't be added.

Apply this fix:

     if (result.data) {
       const results: Record<string, string> = {};
       for (const arbitrator of result.data.arbitrators) {
-        resultMap[arbitrator.address_] = arbitrator.publicKey;
+        results[arbitrator.address_] = arbitrator.publicKey;
       }

       setResultMap((prev) => ({ ...prev, ...results }));
     }
🤖 Prompt for AI Agents
In website/src/hooks/subsquid/useArbitratorPublicKeys.tsx around lines 16 to 25,
the effect loop mistakenly writes to the outer state variable `resultMap`
instead of the local `results` accumulator, leaving `results` empty and causing
setResultMap to merge no new data; change the assignment inside the loop to
write to the local `results` object (i.e., results[arbitrator.address_] =
arbitrator.publicKey), keep the existing results typing, then call
setResultMap(prev => ({ ...prev, ...results })) as-is so the new arbitrator
entries are merged into state.

Comment on lines 7 to 10
export default function useCreatorTakenJobs(
workerAddress: string,
orderBy?: OrderByType
) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Function name mismatch.

The function is declared as useCreatorTakenJobs but the file is named useWorkerApplications.tsx. This will cause import errors when other modules try to import this hook.

Apply this diff:

-export default function useCreatorTakenJobs(
+export default function useWorkerApplications(
   workerAddress: string,
   orderBy?: OrderByType
 ) {
📝 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
export default function useCreatorTakenJobs(
workerAddress: string,
orderBy?: OrderByType
) {
export default function useWorkerApplications(
workerAddress: string,
orderBy?: OrderByType
) {
🤖 Prompt for AI Agents
In website/src/hooks/subsquid/useWorkerApplications.tsx around lines 7 to 10,
the default-exported function is named useCreatorTakenJobs which mismatches the
filename and will break imports; rename the function to useWorkerApplications
(and update any internal references) so the default export matches the file
name, and ensure any callers/imports elsewhere are updated accordingly.

Comment on lines 7 to 14
export default function useCreatorDisputedJobs(
creatorAddress: string,
orderBy?: OrderByType
) {
const { data, ...rest } = useQuery(GET_WORKER_DISPUTED_JOBS, {
const [result] = useQuery({
query: GET_WORKER_DISPUTED_JOBS,
variables: { creatorAddress, ...(orderBy && { orderBy }) },
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Function name and parameter mismatches.

Multiple critical issues:

  1. Function name mismatch: Function is declared as useCreatorDisputedJobs but the file is named useWorkerDisputedJobs.tsx. This will cause import errors.
  2. Parameter name mismatch: Parameter is named creatorAddress but the query GET_WORKER_DISPUTED_JOBS expects a $worker variable (see query definition at website/src/hooks/subsquid/queries.ts:222-228).
  3. Variable mismatch: Line 13 passes creatorAddress but the query expects worker or workerAddress.

Apply this diff to fix all issues:

-export default function useCreatorDisputedJobs(
-  creatorAddress: string,
+export default function useWorkerDisputedJobs(
+  workerAddress: string,
   orderBy?: OrderByType
 ) {
   const [result] = useQuery({
     query: GET_WORKER_DISPUTED_JOBS,
-    variables: { creatorAddress, ...(orderBy && { orderBy }) },
+    variables: { worker: workerAddress, ...(orderBy && { orderBy }) },
   });
📝 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
export default function useCreatorDisputedJobs(
creatorAddress: string,
orderBy?: OrderByType
) {
const { data, ...rest } = useQuery(GET_WORKER_DISPUTED_JOBS, {
const [result] = useQuery({
query: GET_WORKER_DISPUTED_JOBS,
variables: { creatorAddress, ...(orderBy && { orderBy }) },
});
export default function useWorkerDisputedJobs(
workerAddress: string,
orderBy?: OrderByType
) {
const [result] = useQuery({
query: GET_WORKER_DISPUTED_JOBS,
variables: { worker: workerAddress, ...(orderBy && { orderBy }) },
});
🤖 Prompt for AI Agents
In website/src/hooks/subsquid/useWorkerDisputedJobs.tsx around lines 7 to 14,
the exported function name and parameter/variable names do not match the file
and the GraphQL query: rename the function to export default function
useWorkerDisputedJobs(workerAddress: string, orderBy?: OrderByType) and change
the variables passed to the query to use the expected worker variable (e.g.,
variables: { worker: workerAddress, ...(orderBy && { orderBy }) }) so the
exported name, parameter name, and GraphQL variable all align.

// Create a server-side URQL client
export function createServerUrqlClient() {
return new Client({
url: process.env.NEXT_PUBLIC_SUBSQUID_API_URL || '',
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add validation for required environment variable.

Falling back to an empty string when NEXT_PUBLIC_SUBSQUID_API_URL is missing will cause runtime errors when the client attempts to make requests. Consider throwing an error or providing a more robust fallback.

Apply this diff:

 export function createServerUrqlClient() {
+  const url = process.env.NEXT_PUBLIC_SUBSQUID_API_URL;
+  if (!url) {
+    throw new Error('NEXT_PUBLIC_SUBSQUID_API_URL environment variable is required');
+  }
+
   return new Client({
-    url: process.env.NEXT_PUBLIC_SUBSQUID_API_URL || '',
+    url,
     exchanges: [cacheExchange, fetchExchange],
📝 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
url: process.env.NEXT_PUBLIC_SUBSQUID_API_URL || '',
export function createServerUrqlClient() {
const url = process.env.NEXT_PUBLIC_SUBSQUID_API_URL;
if (!url) {
throw new Error('NEXT_PUBLIC_SUBSQUID_API_URL environment variable is required');
}
return new Client({
url,
exchanges: [cacheExchange, fetchExchange],
});
}
🤖 Prompt for AI Agents
In website/src/lib/urql-server.ts around line 6, the code currently falls back
to an empty string for url: process.env.NEXT_PUBLIC_SUBSQUID_API_URL || '',
which can cause runtime request failures; change this to validate the
environment variable at startup and fail fast: if
process.env.NEXT_PUBLIC_SUBSQUID_API_URL is undefined or empty, throw a clear
Error (including the variable name and instructions) or return early so the
server won't start with an invalid URL, otherwise assign the env value; ensure
the change surfaces at build/start time rather than allowing an empty string to
propagate to the client.

Copy link

@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.

Review continued from previous batch...

Comment on lines 24 to 29
query: GET_CREATOR_DISPUTED_JOBS,
variables: {
creatorAddress: '0xCreator1',
offset: 0,
limit: 1000,
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify mock variables match the actual hook signature.

The mock includes offset and limit variables (lines 26-28), but the typical pattern for subsquid hooks in this codebase uses orderBy instead (see related hooks like useWorkerCompletedJobs, useCreatorTakenJobs). Additionally, the hook is invoked with object syntax { creatorAddress, offset, limit } (lines 48, 63), but related hooks use positional parameters.

Run the following script to verify the actual signature of useCreatorDisputedJobs:


🏁 Script executed:

#!/bin/bash
# Description: Verify the signature and query variables for useCreatorDisputedJobs

# Find the hook implementation
echo "=== Hook Implementation ==="
ast-grep --pattern $'export default function useCreatorDisputedJobs($$$) {
  $$$
}'

# Find the query definition
echo "=== Query Definition ==="
rg -A 5 'GET_CREATOR_DISPUTED_JOBS'

Length of output: 5525


Update test to use orderBy and positional args for useCreatorDisputedJobs
The mock for GET_CREATOR_DISPUTED_JOBS currently passes offset/limit and calls the hook with an object, but useCreatorDisputedJobs is defined as (creatorAddress: string, orderBy?: OrderByType) and the query only accepts $orderBy. Change the test’s variables to:

variables: {
  creatorAddress: '0xCreator1',
  ...(orderBy && { orderBy }),
},

and invoke the hook as:

useCreatorDisputedJobs('0xCreator1', orderByParam)

to match the hook signature and GraphQL parameters.

🤖 Prompt for AI Agents
In website/__tests__/hooks/subsquid/useCreatorDisputedJobs.test.tsx around lines
24 to 29, the test mock is using offset/limit and calling the hook with an
object, but the real hook signature is useCreatorDisputedJobs(creatorAddress:
string, orderBy?: OrderByType) and the GraphQL query only accepts $orderBy;
update the mocked variables to remove offset/limit and instead include orderBy
conditionally (variables: { creatorAddress: '0xCreator1', ...(orderBy && {
orderBy }) }) and change the hook invocation to call
useCreatorDisputedJobs('0xCreator1', orderByParam) so the test matches the hook
signature and query parameters.

Comment on lines +60 to +93
request: {
query: GET_JOBS,
variables: { first: 10, skip: 0 },
},
result: {
data: {
jobs: [mockJob],
},
},
};

export const mockUserQueryResponse: MockedResponse = {
request: {
query: GET_USER,
variables: { address: mockUser.address },
},
result: {
data: {
user: mockUser,
},
},
};

export const mockUsersQueryResponse: MockedResponse = {
request: {
query: GET_USERS,
variables: { first: 10, skip: 0 },
},
result: {
data: {
users: [mockUser],
},
},
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Update mock variables to match new query signatures.

GET_JOBS / GET_USERS now take $offset and $limit, but these mocks still declare { first, skip }. Apollo’s mock matcher is strict; with the current shape it never finds a match, so any test using these responses will fall through to “no mock found”. Please switch the variable payloads to { offset: ..., limit: ... } to align with the updated queries.

🤖 Prompt for AI Agents
In website/__tests__/setup/mocks/apollo.ts around lines 60 to 93, the mocked
request variable shapes for GET_JOBS and GET_USERS still use { first, skip }
which no longer match the queries; update those mocked request objects to use {
offset: 0, limit: 10 } (or equivalent values) for GET_JOBS and { offset: 0,
limit: 10 } for GET_USERS so the Apollo mock matcher finds the responses.

() => ({
data: data ? (data?.marketplaces[0] as any) : undefined,
...rest,
data: result.data ? (result.data?.marketplaces[0] as any) : undefined,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace as any cast with proper typing.

Using as any bypasses type safety. Consider defining a proper Marketplace type or importing it from the contracts package.

If a Marketplace type exists in @effectiveacceleration/contracts or elsewhere in the codebase, import and use it:

+import type { Marketplace } from '@effectiveacceleration/contracts';
 
 export default function useMarketplace() {
   const [result] = useQuery({
     query: GET_MARKETPLACES,
     variables: {},
   });

   return useMemo(
     () => ({
-      data: result.data ? (result.data?.marketplaces[0] as any) : undefined,
+      data: result.data ? (result.data?.marketplaces[0] as Marketplace) : undefined,
       loading: result.fetching,
       error: result.error
     }),
     [result]
   );
 }
📝 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
data: result.data ? (result.data?.marketplaces[0] as any) : undefined,
import type { Marketplace } from '@effectiveacceleration/contracts';
export default function useMarketplace() {
const [result] = useQuery({
query: GET_MARKETPLACES,
variables: {},
});
return useMemo(
() => ({
data: result.data
? (result.data.marketplaces[0] as Marketplace)
: undefined,
loading: result.fetching,
error: result.error
}),
[result]
);
}
🤖 Prompt for AI Agents
In website/src/hooks/subsquid/useMarketplace.tsx around line 13, the code casts
result.data?.marketplaces[0] to any which bypasses TypeScript safety; replace
the as any with a proper Marketplace type by importing Marketplace (or defining
an interface) from @effectiveacceleration/contracts (or the appropriate module),
use that type for the GraphQL query/result generics so result.data is typed
(e.g., QueryResult<{ marketplaces: Marketplace[] }>), update the hook/return
type to reflect Marketplace | undefined, and remove the as any cast so the
compiler enforces correct typing.

Comment on lines +13 to 22
const [result] = useQuery({
query: GET_USER_JOB_NOTIFICATIONS,
variables: {
userAddress: userAddress ?? '',
minTimestamp: minTimestamp ?? 0,
offset: offset ?? 0,
limit: limit ?? 10,
},
skip: !userAddress || !jobIds.length,
pause: !userAddress || !jobIds.length,
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Restore jobIds in the query variables.

We stop pausing once jobIds.length is truthy, but the request never sends that array to Subsquid. URQL therefore issues the query with $jobIds missing/null, so the jobId_in filter is ignored and we end up pulling notifications for every job the user has. Please add jobIds back into the variables payload (e.g. jobIds, or jobIds: jobIds.length ? jobIds : undefined) before merging.

Apply this diff:

   const [result] = useQuery({
     query: GET_USER_JOB_NOTIFICATIONS,
     variables: {
       userAddress: userAddress ?? '',
+      jobIds,
       minTimestamp: minTimestamp ?? 0,
       offset: offset ?? 0,
       limit: limit ?? 10,
     },
📝 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 [result] = useQuery({
query: GET_USER_JOB_NOTIFICATIONS,
variables: {
userAddress: userAddress ?? '',
minTimestamp: minTimestamp ?? 0,
offset: offset ?? 0,
limit: limit ?? 10,
},
skip: !userAddress || !jobIds.length,
pause: !userAddress || !jobIds.length,
});
const [result] = useQuery({
query: GET_USER_JOB_NOTIFICATIONS,
variables: {
userAddress: userAddress ?? '',
jobIds,
minTimestamp: minTimestamp ?? 0,
offset: offset ?? 0,
limit: limit ?? 10,
},
pause: !userAddress || !jobIds.length,
});
🤖 Prompt for AI Agents
In website/src/hooks/subsquid/useUserJobNotifications.tsx around lines 13 to 22,
the query pauses until jobIds is truthy but the variables object omits jobIds,
causing the $jobIds parameter to be null and the jobId_in filter to be ignored;
add jobIds back into the variables payload (e.g. include jobIds, or jobIds:
jobIds.length ? jobIds : undefined) so the query sends the array when present
and omits it when empty.

- Upgrade multiple package dependencies including React, Next.js, and UI libraries
- Fix Blob construction in useFetchAvatar and useMediaDownloadHandler hooks
- Refactor Markdown components in job chat event displays
- Update class names for consistent styling in message components
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/src/hooks/useMediaDownloadHandler.ts (1)

9-16: History.state manipulation may not work as intended.

This code attempts to define history.state when it's null, but:

  1. Setting writable: false means this property cannot be changed later, which may break browser history functionality
  2. Modern browsers manage history.state internally, and attempting to redefine it with Object.defineProperty may not work or could cause unexpected behavior
  3. The check window.history.state === null is fragile

Consider removing this workaround or explaining why it's necessary. If this is to handle a specific browser issue, document it clearly.

♻️ Duplicate comments (2)
website/package.json (1)

82-87: Restore Next.js and React to runtime dependencies.

next, react, and react-dom now live under devDependencies, so any production install (npm install --production, Vercel, etc.) skips them and the app fails to build/run. Please move all three back into "dependencies" and drop them from "devDependencies".

       "tailwind-merge": "^3.3.1",
-      "tailwindcss-animate": "^1.0.7",
-      "urql": "^5.0.1",
+      "tailwindcss-animate": "^1.0.7",
+      "next": "^15.5.4",
+      "react": "^19.2.0",
+      "react-dom": "^19.2.0",
+      "urql": "^5.0.1",
...
-    "next": "^15.5.4",
...
-    "react": "^19.2.0",
-    "react-dom": "^19.2.0",
website/src/hooks/useMediaDownloadHandler.ts (1)

46-46: Verify the necessity of accessing .buffer.

Same issue as in useFetchAvatar.tsx line 16: the Blob constructor accepts typed arrays directly, and the as ArrayBuffer assertion is potentially unsafe if the property doesn't exist or isn't the expected type.

See the verification script in the review comment for website/src/hooks/useFetchAvatar.tsx line 16.

🧹 Nitpick comments (4)
website/src/hooks/useFetchAvatar.tsx (2)

13-13: Remove unsafe type assertion.

The as any cast on sessionKey bypasses type safety. Consider one of these approaches:

  1. Update safeGetMediaFromIpfs to accept string | undefined
  2. Use a proper type guard or conditional
  3. Document why the type assertion is necessary if it's intentional

16-16: Simplify Blob constructor
Replace new Blob([mediaBytes.buffer as ArrayBuffer], { type: mimeType }) with new Blob([mediaBytes], { type: mimeType }) since Uint8Array is already an ArrayBufferView.

website/src/hooks/useMediaDownloadHandler.ts (2)

61-61: Avoid unsafe type assertion for event parameter.

Passing {} as any bypasses type safety. If onhashchange doesn't actually use the event parameter, consider:

  1. Checking if the parameter is optional and calling without arguments
  2. Creating a proper mock event object
  3. Refactoring to extract the hash-handling logic into a separate function

49-49: Consider increasing timeout for URL cleanup.

The 1-second timeout before revoking the blob URL may be insufficient for large files or slow downloads, potentially causing the download to fail.

Consider increasing the timeout to 5-10 seconds or using a more robust approach:

-        setTimeout(() => URL.revokeObjectURL(url), 1000);
+        setTimeout(() => URL.revokeObjectURL(url), 5000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08ead0d and 6470a35.

⛔ Files ignored due to path filters (1)
  • website/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • website/package.json (1 hunks)
  • website/src/app/jobs/[id]/JobChat/Events/DeliveredEvent.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobChat/Events/OwnerMessageEvent.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobChat/Events/WorkerMessageEvent.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobChat/StatusStates/ResultAccepted.tsx (1 hunks)
  • website/src/app/jobs/[id]/JobChat/StatusStates/ResultVerification.tsx (1 hunks)
  • website/src/hooks/useFetchAvatar.tsx (1 hunks)
  • website/src/hooks/useMediaDownloadHandler.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website/src/app/jobs/[id]/JobChat/Events/WorkerMessageEvent.tsx
🔇 Additional comments (4)
website/src/app/jobs/[id]/JobChat/StatusStates/ResultVerification.tsx (1)

156-160: LGTM! Styling successfully moved to container level.

The relocation of text styling from the Markdown component to the wrapper div is correct and aligns with the broader UI consistency refactor across the codebase. Content rendering logic remains unchanged.

website/src/app/jobs/[id]/JobChat/StatusStates/ResultAccepted.tsx (1)

206-210: LGTM! Consistent styling pattern applied.

The styling relocation follows the same pattern as other components in this PR, moving typography classes to the container while preserving content rendering behavior.

website/src/app/jobs/[id]/JobChat/Events/OwnerMessageEvent.tsx (1)

139-143: LGTM! Responsive styling correctly maintained.

The styling relocation properly preserves responsive text sizing (text-sm sm:text-base) while moving other typography classes to the container level, consistent with the refactor pattern.

website/src/app/jobs/[id]/JobChat/Events/DeliveredEvent.tsx (1)

116-120: LGTM! Styling pattern consistently applied.

The relocation of typography classes to the wrapper div, including responsive text sizing (text-xs sm:text-sm), maintains the original presentation while aligning with the broader UI refactor pattern across all message and status components.

- Remove @mui/material and @mui/icons-material packages
- Replace MUI Rating component with custom star rating implementation
- Remove MUI LinearProgress component
- Replace MUI SvgIcon wrappers with direct SVG elements
- Update package.json to reflect removed dependencies
Copy link

@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: 1

🧹 Nitpick comments (3)
website/src/components/TokenSelector/icons/ExternalLinkIcon.tsx (1)

1-17: Consider stronger typing for the props parameter.

The props: any type reduces type safety. Consider using React.SVGProps<SVGSVGElement> to enable proper autocomplete and type checking for SVG attributes.

Apply this diff to improve type safety:

-export const ExternalLinkIcon = (props: any) => {
+export const ExternalLinkIcon = (props: React.SVGProps<SVGSVGElement>) => {
   return (
website/src/components/TokenSelector/icons/EthereumIcon.tsx (1)

1-30: Consider stronger typing for the props parameter.

The props: any type reduces type safety. Consider using React.SVGProps<SVGSVGElement> to enable proper autocomplete and type checking for SVG attributes.

Apply this diff to improve type safety:

-export const EthereumIcon = (props: any) => {
+export const EthereumIcon = (props: React.SVGProps<SVGSVGElement>) => {
   return (
website/src/components/TokenSelector/icons/PinIcon.tsx (1)

1-17: Consider stronger typing for the props parameter.

The props: any type reduces type safety. Consider using React.SVGProps<SVGSVGElement> to enable proper autocomplete and type checking for SVG attributes.

Apply this diff to improve type safety:

-export const PinIcon = (props: any) => {
+export const PinIcon = (props: React.SVGProps<SVGSVGElement>) => {
   return (
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6470a35 and 50c23b2.

📒 Files selected for processing (6)
  • website/package.json (1 hunks)
  • website/src/app/jobs/[id]/JobActions/ApproveButton.tsx (2 hunks)
  • website/src/app/jobs/[id]/JobChatDetails.tsx (0 hunks)
  • website/src/components/TokenSelector/icons/EthereumIcon.tsx (1 hunks)
  • website/src/components/TokenSelector/icons/ExternalLinkIcon.tsx (1 hunks)
  • website/src/components/TokenSelector/icons/PinIcon.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • website/src/app/jobs/[id]/JobChatDetails.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/package.json
🔇 Additional comments (1)
website/src/app/jobs/[id]/JobActions/ApproveButton.tsx (1)

12-12: Verify react-icons compatibility in website/package.json
Ensure the installed react-icons version (in website/package.json) isn’t impacted by the v5.5.0 typing change (IconType → ReactNode); confirm ApproveButton.tsx compiles without JSX/TS errors.

Comment on lines +206 to +244
<div className='flex gap-2'>
{[1, 2, 3, 4, 5].map((value) => (
<button
key={value}
type='button'
onClick={() => setRating(value)}
onMouseEnter={(e) => {
const stars = e.currentTarget.parentElement?.querySelectorAll('button');
stars?.forEach((star, idx) => {
const icon = star.querySelector('svg');
if (idx < value && icon) {
icon.classList.add('text-amber-500');
icon.classList.remove('text-gray-300');
}
});
}}
onMouseLeave={(e) => {
const stars = e.currentTarget.parentElement?.querySelectorAll('button');
stars?.forEach((star, idx) => {
const icon = star.querySelector('svg');
if (idx < rating && icon) {
icon.classList.add('text-amber-400');
icon.classList.remove('text-gray-300', 'text-amber-500');
} else if (icon) {
icon.classList.add('text-gray-300');
icon.classList.remove('text-amber-400', 'text-amber-500');
}
});
}}
className='transition-transform hover:scale-110'
>
{value <= rating ? (
<PiStarFill className='h-8 w-8 text-amber-400' />
) : (
<PiStar className='h-8 w-8 text-gray-300 dark:text-gray-600' />
)}
</button>
))}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Replace direct DOM manipulation with React state.

The current implementation directly manipulates the DOM via classList in event handlers, which violates React's declarative paradigm and creates several critical issues:

  • State inconsistency: Visual state (classList) can diverge from React state during re-renders, causing flickers or lost hover effects.
  • Race conditions: classList changes conflict with React's reconciliation, especially during rapid hover events.
  • Fragile queries: querySelector/querySelectorAll assumptions about DOM structure can break and return null (NPE risk).
  • Maintainability: Direct DOM manipulation makes the component harder to reason about and test.

Refactor to use React state for hover tracking:

 export function ApproveButton({
   address,
   job,
   ...rest
 }: ApproveButtonProps & React.ComponentPropsWithoutRef<'div'>) {
   const Config = useConfig();
   const [review, setReview] = useState<string>('');
   const [rating, setRating] = useState<number>(0);
+  const [hoveredRating, setHoveredRating] = useState<number>(0);

   const [isApproving, setIsApproving] = useState(false);

Then update the star rendering logic:

                           <div className='rounded-xl border border-gray-200 bg-gradient-to-br from-gray-50 to-gray-100 p-4 dark:border-gray-700 dark:from-gray-800/50 dark:to-gray-900/50'>
-                            <div className='flex gap-2'>
+                            <div 
+                              className='flex gap-2'
+                              onMouseLeave={() => setHoveredRating(0)}
+                            >
                               {[1, 2, 3, 4, 5].map((value) => (
                                 <button
                                   key={value}
                                   type='button'
                                   onClick={() => setRating(value)}
-                                  onMouseEnter={(e) => {
-                                    const stars = e.currentTarget.parentElement?.querySelectorAll('button');
-                                    stars?.forEach((star, idx) => {
-                                      const icon = star.querySelector('svg');
-                                      if (idx < value && icon) {
-                                        icon.classList.add('text-amber-500');
-                                        icon.classList.remove('text-gray-300');
-                                      }
-                                    });
-                                  }}
-                                  onMouseLeave={(e) => {
-                                    const stars = e.currentTarget.parentElement?.querySelectorAll('button');
-                                    stars?.forEach((star, idx) => {
-                                      const icon = star.querySelector('svg');
-                                      if (idx < rating && icon) {
-                                        icon.classList.add('text-amber-400');
-                                        icon.classList.remove('text-gray-300', 'text-amber-500');
-                                      } else if (icon) {
-                                        icon.classList.add('text-gray-300');
-                                        icon.classList.remove('text-amber-400', 'text-amber-500');
-                                      }
-                                    });
-                                  }}
+                                  onMouseEnter={() => setHoveredRating(value)}
                                   className='transition-transform hover:scale-110'
                                 >
-                                  {value <= rating ? (
-                                    <PiStarFill className='h-8 w-8 text-amber-400' />
+                                  {value <= (hoveredRating || rating) ? (
+                                    <PiStarFill 
+                                      className={`h-8 w-8 ${
+                                        hoveredRating > 0 && value <= hoveredRating
+                                          ? 'text-amber-500'
+                                          : 'text-amber-400'
+                                      }`}
+                                    />
                                   ) : (
                                     <PiStar className='h-8 w-8 text-gray-300 dark:text-gray-600' />
                                   )}
                                 </button>
                               ))}
                             </div>
                           </div>

This approach:

  • Uses hoveredRating state to track hover interactions declaratively
  • Removes all direct DOM manipulation
  • Ensures visual state stays in sync with React state
  • Eliminates NPE risks from querySelector
  • Makes the component easier to test and maintain

- Removed @radix-ui/react-separator and @radix-ui/react-slider
- Removed @urql/exchange-graphcache
- Dependencies are no longer used in the project and can be safely removed to reduce bundle size
- Replace separate test workflows with single coverage workflow
- Use matrix strategy to handle both packages
- Update Node.js version to 22
- Handle different coverage file locations
- Enable parallel coverage uploads to Coveralls
- Add workflow completion step for Coveralls
- Removed conditional logic for running coverage commands
- Standardized on `npm run test:coverage` for both packages
- Reduced complexity in workflow step execution
The workflow now only runs on master branch pushes and pull requests.
This change ensures Lighthouse tests are only triggered for the primary
branch, avoiding duplicate checks on feature branches.
- Configure .solcover.js to skip specific contracts and directories
- Migrate jest.config.ts to .js format with commonjs exports
- Update @types/react dependencies to stable versions
Copy link

@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

♻️ Duplicate comments (1)
website/package.json (1)

78-79: React must be in dependencies, not devDependencies.

React and react-dom are currently in devDependencies, but Next.js requires them as runtime dependencies. This will break production builds when npm install --production is run (e.g., on Vercel or other deployment platforms), as these packages will be excluded.

Move both packages to the dependencies section:

+  "dependencies": {
+    ...existing dependencies...
+    "react": "^19.2.0",
+    "react-dom": "^19.2.0",
+  },
   "devDependencies": {
     ...
-    "react": "^19.2.0",
-    "react-dom": "^19.2.0",
     ...
   }
🧹 Nitpick comments (1)
.github/workflows/lighthouse.yml (1)

24-34: Optional: Consider using defaults.run.working-directory for cleaner code.

Each step currently changes to the website directory with cd website &&. You could simplify this by adding a job-level default:

 jobs:
   lighthouse:
     runs-on: ubuntu-latest
+    defaults:
+      run:
+        working-directory: website

     steps:
       - name: Checkout code
         uses: actions/checkout@v4

       - name: Setup Node.js
         uses: actions/setup-node@v4
         with:
           node-version: '22'
           cache: 'npm'
           cache-dependency-path: website/package-lock.json

       - name: Install dependencies
-        run: cd website && npm ci
+        run: npm ci

       - name: Build site
-        run: cd website && npm run build
+        run: npm run build

       - name: Start server
         run: |
-          cd website
           npm start &
           npx wait-on http://localhost:3000 --timeout 60000
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50c23b2 and bf8babc.

⛔ Files ignored due to path filters (1)
  • website/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • .github/dependabot.yml (1 hunks)
  • .github/workflows/coverage.yml (1 hunks)
  • .github/workflows/lighthouse.yml (1 hunks)
  • contract/.solcover.js (1 hunks)
  • contract/package.json (1 hunks)
  • website/jest.config.js (1 hunks)
  • website/lighthouserc.js (1 hunks)
  • website/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • .github/workflows/coverage.yml
  • .github/dependabot.yml
  • contract/.solcover.js
🔇 Additional comments (8)
.github/workflows/lighthouse.yml (1)

1-43: LGTM! Lighthouse CI workflow is well-structured.

The workflow correctly sets up the environment, builds the site, starts the server with a wait mechanism, and runs Lighthouse CI with the configuration file.

website/lighthouserc.js (1)

1-23: LGTM! Lighthouse CI configuration is appropriate.

The configuration uses reasonable thresholds and settings for CI environment. The 'warn' level for assertions won't fail the build but provides visibility into performance metrics.

website/jest.config.js (3)

1-6: LGTM!

The Next.js Jest integration follows the recommended pattern, enabling Next.js config and environment loading during tests.


31-34: LGTM! Correct handling of ESM packages.

The transformIgnorePatterns correctly allows Jest to transform wagmi, viem, and @TanStack packages, which are ESM-only modules that require transformation in the Jest environment.


37-38: LGTM!

The export pattern correctly uses createJestConfig to ensure Next.js async config loading is handled properly.

website/package.json (3)

14-16: LGTM!

The test scripts are standard Jest patterns and properly integrate with the new jest.config.js configuration.


53-56: Apollo → URQL migration complete
No remaining Apollo imports, requires, ApolloClient, or ApolloProvider references detected.


78-79: Verify and complete React 19 upgrade

  • Upgrade bundler/Babel/TypeScript configs and frameworks (Next.js, Vite, CRA) to versions supporting React 19 and the new JSX runtime
  • Run React 19 codemods (API removals/renames) and TypeScript codemods (e.g., npx types-react-codemod@latest preset-19 ./src)
  • Replace ReactDOM.render/hydrate → createRoot/hydrateRoot (+ use onUncaughtError/onCaughtError) and root.unmount()
  • Migrate legacy APIs: defaultProps on function components, childContextTypes/contextTypes, string refs → modern hooks/APIs
  • Update error-reporting integrations to use window.reportError/console.error or createRoot error hooks; test Error Boundaries
  • Run full test suite in StrictMode; fix render-phase side effects, Suspense/use(...) patterns, TS signature errors
  • Update all React-integrated dependencies (testing libraries, react-is, devtools, SSR frameworks) to React 19–compatible versions

Comment on lines +7 to +8
// Don't fail on Chrome extensions or other issues
skipAudits: ['uses-http2'],
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify the comment about skipped audits.

The comment mentions "Chrome extensions or other issues," but the uses-http2 audit specifically checks whether the server uses the HTTP/2 protocol, which is unrelated to Chrome extensions.

Apply this diff to clarify the comment:

       settings: {
-        // Don't fail on Chrome extensions or other issues
+        // Skip HTTP/2 audit for local testing
         skipAudits: ['uses-http2'],
       },
📝 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
// Don't fail on Chrome extensions or other issues
skipAudits: ['uses-http2'],
settings: {
// Skip HTTP/2 audit for local testing
skipAudits: ['uses-http2'],
},
🤖 Prompt for AI Agents
In website/lighthouserc.js around lines 7 to 8, the existing comment "Don't fail
on Chrome extensions or other issues" is misleading for the skipAudits entry
since uses-http2 checks whether the server uses HTTP/2 (not Chrome extensions);
update the comment to explicitly state that the uses-http2 audit is being
skipped because the hosting or CI environment doesn't require/guarantee HTTP/2
(or similar rationale used in the project) so it doesn't fail the Lighthouse
run, leaving the skipAudits line intact.

"feed": "^5.1.0",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"next": "^15.5.4",
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify Next.js 15 breaking changes and migration requirements.

Next.js 15 is a major version upgrade that typically includes breaking changes. Ensure all breaking changes have been addressed in the codebase.


🌐 Web query:

What are the breaking changes in Next.js 15 and what migration steps are required from Next.js 14?

💡 Result:

Short summary — main breaking changes in Next.js 15 and the migration steps from 14.

Breaking changes (highest-impact)

  • Async Request APIs: request-scoped APIs that were synchronous now must be awaited (cookies, headers, draftMode, params/searchParams in pages/layouts/route handlers/generators). Synchronous access is temporarily warned but will be removed. [1][2]
  • Caching semantics: fetch, GET Route Handlers, and client navigations are not cached by default (default behaves like no-store). You must explicitly opt into static/caching behavior (e.g., export const dynamic = 'force-static' or specify cache/stale options). [1][3]
  • React minimum bumped: Next 15 targets React 19 — some React hooks changed (useFormState → useActionState, useFormStatus keys expanded). Upgrade React if you rely on those APIs. [2]
  • Tooling/bundler changes (developer-facing): Turbopack is promoted (dev) and Turbopack/rspack configuration locations changed — check next.config updates if you depend on custom bundler config. [1]

Required migration steps (practical checklist)

  1. Read/prepare:
    • Review the official Next.js 15 upgrade guide and release notes. [2][1]
  2. Upgrade packages:
    • npm/yarn: npm i next@latest react@latest react-dom@latest eslint-config-next@latest (minimum React 19). [2]
  3. Run codemods:
    • Run the Next 15 codemods to automate common changes:
      npx @next/codemod@canary upgrade latest
      npx @next/codemod@canary next-async-request-api .
      These convert synchronous request-APIs to async and apply other automated fixes. [2][4]
  4. Fix async request-API usage:
    • Replace synchronous calls with await (example: const cookieStore = await cookies();). Update any uses of headers(), cookies(), draftMode(), params/searchParams in page/layout/route/generator functions to be async. Ensure components that call them are async where needed. [1][3]
  5. Update caching behavior:
    • Audit places relying on implicit caching (fetch, GET handlers, client navigations). Explicitly set caching/dynamic behavior:
      • For route handlers/pages you want cached/static: export const dynamic = 'force-static' or use fetch cache options (cache: 'force-cache' / { next: { revalidate } } / set staleTimes as appropriate). For client data, set stale times or client-side caching explicitly. [1][3]
  6. Address React hook changes & types:
    • Replace deprecated React hooks (useFormState → useActionState) and update usages of useFormStatus to handle the new keys. Update @types/react/@types/react-dom if using TypeScript. [2]
  7. Adjust bundler/dev-server config if needed:
    • If you relied on experimental.turbo or custom webpack config, move Turbopack settings to the new turbopack key in next.config.ts or follow guidance for Rspack plugin. Verify dev server behavior after upgrade. [1]
  8. Test thoroughly:
    • Run unit/integration tests and manual QA for pages, route handlers, redirects, middleware, and any analytics/monitoring that run early (new client instrumentation hooks exist). Fix any runtime warnings about synchronous API usage. [1][2]
  9. Fallbacks & gradual migration:
    • The docs note temporary synchronous access with warnings — you can migrate in stages, but remove warns and address async usage before the next major removal. Use the codemod output to find remaining manual edits. [3][2]

If you want, I can:

  • run the async-request codemod locally and show example diffs for a sample file you paste, or
  • search your repo for usages of cookies()/headers()/draftMode/params to produce a migration plan.

Sources:

  • Next.js 15 release blog (breaking changes summary). [1]
  • Next.js upgrade guide — Upgrading from 14 → 15 (codemods, React 19 notes). [2]
  • Next.js 15 RC / migration details (async APIs, warnings, codemod command). [3]

References:
[1] Next.js blog — Next 15 release.
[2] Next.js docs — Upgrading: Version 15.
[3] Next.js blog — Next 15 RC notes (async request APIs and codemod).


Apply Next.js 15 migration codemods and fix breaking changes

  • Run npx @next/codemod@canary upgrade latest and npx @next/codemod@canary next-async-request-api .
  • Convert synchronous request APIs (cookies(), headers(), draftMode(), params/searchParams) to await in page/layout/route handlers
  • Explicitly configure caching/static behavior (e.g. export const dynamic = 'force-static' or fetch cache options)
  • Upgrade to React 19+, update deprecated hooks (e.g. useFormStateuseActionState)
  • Move any custom bundler config under the new turbopack key in next.config.* and verify dev server
  • Run full test suite and fix any runtime warnings
🤖 Prompt for AI Agents
In website/package.json around line 74 the Next.js dependency was bumped to
15.5.4 but the codebase hasn’t been migrated; run the Next 15 codemods (npx
@next/codemod@canary upgrade latest and npx @next/codemod@canary
next-async-request-api .), then update all uses of synchronous request APIs
(cookies(), headers(), draftMode(), params/searchParams) to await their async
versions in pages/layouts/routes, explicitly set component caching/static
behavior (e.g. export const dynamic = 'force-static' or use fetch cache
options), upgrade React to v19+ and replace deprecated hooks (e.g. useFormState
→ useActionState), move any custom bundler config under the new turbopack key in
next.config.* and verify dev server, and finally run the full test suite and fix
any runtime warnings.

- Configure mocha-junit-reporter for contract tests in CI
- Set up jest-junit reporter for website tests
- Update coverage scripts to create test-results directories
- Add GitHub Actions step to publish test results
- Ignore test-results directories in both packages
- Replace all Jest mocks with Vitest equivalents
- Update test utilities and setup files
- Configure Vitest with proper aliases and coverage settings
- Remove Jest configuration and dependencies
- Update package scripts to use Vitest commands
- Replace MockedProvider with custom URQL mock implementation
- Remove redundant Apollo imports and ReactNode wrappers
- Standardize mock query structure and wrapper creation
- Update test assertions to match new mock data structure
- Remove overly specific assertions that duplicated mock data
- Fix localStorage mock implementation in useUserNotifications.test.tsx
- Update NextResponse mocks to properly handle text() and json() methods
- Simplify hook tests by removing unnecessary loading state checks
- Fix parameter handling in subsquid hooks tests
- Update component tests to use direct prop passing instead of hooks
- Improve urql mock client implementation for better query matching
- Skip several tests that require complex mocking setups
- Fix type mismatches in test data structures
- Update test utility providers and wrappers
Copy link

@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: 6

♻️ Duplicate comments (2)
website/__tests__/lib/utils.test.ts (1)

66-68: Test validates potentially incorrect behavior.

This test expects absoluteUrl('about') to produce 'https://example.comabout' (no slash between domain and path), which validates the current implementation but is likely incorrect behavior as noted in the previous review.

website/package.json (1)

83-84: Move React and React-DOM to dependencies

Next.js requires React at runtime; production installs skip devDependencies.

In website/package.json:

  "dependencies": {
+   "react": "^19.2.0",
+   "react-dom": "^19.2.0",
  },
  "devDependencies": {
-   "react": "^19.2.0",
-   "react-dom": "^19.2.0",
🧹 Nitpick comments (18)
website/__tests__/lib/utils.test.ts (2)

71-149: Expand test coverage for all event types.

The test suite covers most JobEventType values but is missing tests for:

  • JobEventType.Signed
  • JobEventType.Rated
  • JobEventType.Refunded
  • JobEventType.ArbitrationRefused

Consider adding test cases for these event types to ensure complete coverage of the EventTextMap function.

Add test cases for the missing event types:

it('should return correct text for Signed event', () => {
  expect(EventTextMap(JobEventType.Signed, '150')).toBe(
    'Job #150 has been signed.'
  );
});

it('should return correct text for Rated event', () => {
  expect(EventTextMap(JobEventType.Rated, '250')).toBe(
    'Job #250 has been rated.'
  );
});

it('should return correct text for Refunded event', () => {
  expect(EventTextMap(JobEventType.Refunded, '350')).toBe(
    'Job #350 has been refunded.'
  );
});

it('should return correct text for ArbitrationRefused event', () => {
  expect(EventTextMap(JobEventType.ArbitrationRefused, '450')).toBe(
    'Job #450 arbitration has been refused.'
  );
});

176-182: Consider verifying error handling side effects.

The test verifies that isImageValid returns false on fetch error, but doesn't verify that the error was logged to console or captured by Sentry (both called in the production code).

Consider asserting the side effects to ensure complete error handling verification:

 it('should return false on fetch error', async () => {
   (global.fetch as any).mockRejectedValue(new Error('Network error'));
   const consoleSpy = vi.spyOn(console, 'error').mockImplementation();
   const result = await isImageValid('https://example.com/error.jpg');
   expect(result).toBe(false);
+  expect(consoleSpy).toHaveBeenCalledWith(
+    'Error checking image URL:',
+    expect.any(Error)
+  );
   consoleSpy.mockRestore();
 });

Note: You may also want to mock Sentry.captureException to verify it was called with the error.

website/__tests__/hooks/useConfig.test.ts (2)

1-5: Remove unused import.

The afterEach function is imported but never used in the test suite.

Apply this diff to remove the unused import:

-import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
+import { vi, describe, it, expect, beforeEach } from 'vitest';

60-68: Strengthen the assertion for the disconnected wallet scenario.

When the wallet is not connected, the hook defaults to 'Arbitrum One' config (per the implementation). Consider verifying the specific config values rather than just checking if the result is defined.

Apply this diff to add a more specific assertion:

   it('should return default config when wallet not connected', () => {
     (useWalletClient as any).mockReturnValue({
       data: undefined,
     });
 
     const { result } = renderHook(() => useConfig());
 
     expect(result.current).toBeDefined();
+    expect(result.current?.marketplaceAddress).toBe('0xArbitrumMarketplace');
   });
website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (1)

38-50: LGTM! Test correctly handles async state updates.

The test invokes the hook with the correct array parameter signature (useUsersByAddresses(['0xUser1', '0xUser2'])) and appropriately uses waitFor to handle the hook's internal state updates. The comment explaining the async behavior is helpful.

Consider adding more specific assertions to validate the returned user data structure:

     await waitFor(() => {
       // useUsersByAddresses uses state and effects, so we need to wait for updates
       expect(result.current.data).toBeDefined();
+      expect(result.current.data?.['0xUser1']).toEqual(mockUser1);
+      expect(result.current.data?.['0xUser2']).toEqual(mockUser2);
     });

This would more thoroughly validate that the hook returns the expected user objects keyed by address.

website/__tests__/hooks/subsquid/useJobSearch.test.tsx (3)

1-4: Remove unused waitFor import.

The test imports waitFor but never uses it (line 53 shows synchronous assertions only). This is a minor cleanup item.

Apply this diff:

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

6-19: Consider using the shared mockJob from test mocks.

The test defines a local mockJob object, but there's already a more comprehensive mockJob exported from website/__tests__/setup/mocks/urql.tsx (lines 69-89) that includes additional fields like chainId, maxTime, deliveryMethod, timestamp, and events. Using the shared mock improves consistency across tests and reduces duplication.

Apply this diff:

+import { mockJob } from '../../setup/mocks/urql';
+
-const mockJob = {
-  id: '1',
-  state: 0,
-  title: 'Search Result Job',
-  tags: ['digital-audio'],
-  content: 'Test content with search term',
-  roles: {
-    creator: '0xCreator',
-    worker: null,
-    arbitrator: '0xArbitrator',
-  },
-  amount: '1000000',
-  token: '0xUSDC',
-};

If you need test-specific overrides, you can spread the shared mock:

const testJob = { ...mockJob, title: 'Search Result Job' };

41-57: Expand test coverage for the hook.

The test only validates the happy path with minimal assertions. Consider adding test cases for:

  • Error handling when the query fails
  • Different search criteria (tags, amounts, multiple filters)
  • Verification of the returned data structure/content (currently only checks data is defined)
  • Edge cases like empty results or limit/offset behavior

Example additional test cases:

it('should return empty array for no matches', async () => {
  const emptyMocks = [{
    query: GET_JOB_SEARCH({ search: 'state_eq: 999', orderBy: 'timestamp_ASC', limit: 100, offset: 0 }),
    variables: {},
    data: { jobs: [] },
  }];
  const emptyWrapper = createUrqlWrapper(emptyMocks);
  
  const { result } = renderHook(
    () => useJobSearch({ jobSearch: { state: 999 }, orderBy: 'timestamp_ASC', limit: 100, offset: 0 }),
    { wrapper: emptyWrapper }
  );
  
  expect(result.current.data).toEqual([]);
  expect(result.current.loading).toBe(false);
});

it('should handle query errors', async () => {
  const errorMocks = [{
    query: GET_JOB_SEARCH({ search: 'state_eq: 0', orderBy: 'timestamp_ASC', limit: 100, offset: 0 }),
    variables: {},
    error: new Error('GraphQL error'),
  }];
  const errorWrapper = createUrqlWrapper(errorMocks);
  
  const { result } = renderHook(
    () => useJobSearch({ jobSearch: { state: 0 }, orderBy: 'timestamp_ASC', limit: 100, offset: 0 }),
    { wrapper: errorWrapper }
  );
  
  expect(result.current.error).toBeDefined();
  expect(result.current.data).toBeUndefined();
});
website/__tests__/pages/ConnectWallet.test.tsx (1)

22-70: Consider accessibility-focused queries when enabling tests.

When you enable these tests, consider using getByRole instead of getByText for better accessibility coverage:

// Instead of:
expect(screen.getByText(/connect/i)).toBeInTheDocument();

// Use:
expect(screen.getByRole('button', { name: /connect/i })).toBeInTheDocument();

This ensures the interactive elements are properly exposed to assistive technologies.

website/__tests__/pages/PostJobPage.test.tsx (1)

31-110: Improve test robustness when enabling.

When you enable these tests, consider these improvements:

  1. Use more specific queries: Prefer getByRole over getByLabelText for better accessibility testing:
// Instead of:
screen.getByLabelText(/title/i)
// Use:
screen.getByRole('textbox', { name: /title/i })
  1. Complete validation test (line 38): The test expects validation errors but only checks for one. Either add more validation checks or rename the test to be more specific.

  2. Tag selection test (lines 69-80): Assumes specific tag text "digital audio" exists. Consider making this more resilient by checking for any tag selection mechanism.

website/__tests__/api/circulating_supply.test.ts (4)

15-35: Consider simplifying the ethers mock structure.

The mock duplicates the Contract and utility functions at both the ethers.ethers and top-level exports. If the API route only uses one import style, you could simplify this. However, this duplication is safe and ensures compatibility with both import patterns.


42-56: Strengthen supply calculation assertions.

The tests verify that the supply value is a number >= 0, but don't validate the actual calculation logic. Consider asserting against expected values based on the mocked balances:

it('should calculate correct circulating supply', async () => {
  const response = await GET();
  const data = await response.text();
  
  // Based on mocks: totalSupply (10000) - burnBalance (1000) = 9000
  // (in actual tokens: 10000 - 1000 = 9000 tokens)
  const expectedSupply = 9000;
  expect(Number(data)).toBeCloseTo(expectedSupply, 1);
});

58-67: Caching test doesn't validate actual caching behavior.

This test only verifies that two calls return the same value, which would be true even without caching (deterministic mock). To properly test caching:

  1. Track how many times the Contract methods are called
  2. Verify they're only called once despite multiple GET() calls
  3. Or test cache invalidation after a time period
it('should cache the result', async () => {
  const mockBalanceOf = vi.fn().mockResolvedValue(BigInt('1000000000000000000000'));
  vi.mocked(Contract).mockImplementation(() => ({
    balanceOf: mockBalanceOf,
    totalSupply: vi.fn().mockResolvedValue(BigInt('10000000000000000000000')),
  }));

  await GET();
  await GET();

  // Verify contract methods called only once due to caching
  expect(mockBalanceOf).toHaveBeenCalledTimes(1);
});

69-77: Error handling test is incomplete.

The test acknowledges it's incomplete (lines 70-71) and only checks that a response exists. To properly test error handling:

it('should handle errors gracefully', async () => {
  // Mock contract to throw error
  vi.mocked(Contract).mockImplementation(() => ({
    balanceOf: vi.fn().mockRejectedValue(new Error('RPC error')),
    totalSupply: vi.fn().mockResolvedValue(BigInt('10000000000000000000000')),
  }));

  const response = await GET();
  
  expect(response.status).toBe(500);
  const data = await response.text();
  expect(data).toBeDefined();
});
website/__tests__/hooks/subsquid/useArbitrators.test.tsx (1)

69-78: Strengthen assertion for default limit test.

The test only checks that the result is defined (line 76), which doesn't verify the default limit behavior. Since the hook converts limit: 0 to limit: 1000 (see useArbitrators.tsx line 8), you should verify the returned data matches the mock configured for that limit:

it('should use default limit when 0', () => {
  const { result } = renderHook(
    () => useArbitrators(0, 0),
    { wrapper }
  );

  expect(result.current.loading).toBe(false);
  expect(result.current.data).toBeDefined();
  expect(result.current.data?.length).toBe(2); // Based on mockArbitrators
});
website/__tests__/pages/TakeJobButton.test.tsx (1)

139-143: Add missing address prop for consistency.

The test at line 139 omits the address prop that other tests include (e.g., lines 77, 88, 101, 126). While the component may work without it, inconsistent prop usage across tests can mask issues and reduce test reliability.

Apply this diff:

-    render(<TakeJobButton job={takenJob} />);
+    render(<TakeJobButton address="0xWorker" job={takenJob} events={mockEvents} />);

Similarly, update line 158:

-    render(<TakeJobButton job={jobWithCollateral} />);
+    render(<TakeJobButton address="0xWorker" job={jobWithCollateral} events={mockEvents} />);
website/__tests__/api/market_cap.test.ts (1)

21-40: Remove duplicate ethers mocking.

The ethers library is mocked twice: once nested under ethers.Contract (lines 23-31) and again as direct exports Contract, JsonRpcProvider, etc. (lines 32-40). This duplication is confusing and unnecessary.

Simplify to a single mock structure:

 vi.mock('ethers', () => ({
-  ethers: {
-    Contract: vi.fn().mockImplementation(() => ({
-      totalSupply: vi.fn().mockResolvedValue(BigInt('10000000000000000000000')),
-      balanceOf: vi.fn().mockResolvedValue(BigInt('1000000000000000000000')),
-    })),
-    JsonRpcProvider: vi.fn(),
-    formatUnits: vi.fn((value) => (Number(value) / 1e18).toString()),
-    formatEther: vi.fn((value) => (Number(value) / 1e18).toString()),
-    parseEther: vi.fn((value) => BigInt(value) * BigInt(10 ** 18)),
-  },
   Contract: vi.fn().mockImplementation(() => ({
     totalSupply: vi.fn().mockResolvedValue(BigInt('10000000000000000000000')),
     balanceOf: vi.fn().mockResolvedValue(BigInt('1000000000000000000000')),
   })),
   JsonRpcProvider: vi.fn(),
   formatUnits: vi.fn((value) => (Number(value) / 1e18).toString()),
   formatEther: vi.fn((value) => (Number(value) / 1e18).toString()),
   parseEther: vi.fn((value) => BigInt(value) * BigInt(10 ** 18)),
 }));
website/__tests__/setup/mocks/urql.tsx (1)

44-51: Update misleading comment.

The comment on line 44 says "Return empty data if no mock found", but the code actually returns an error. This discrepancy can confuse future maintainers.

Update the comment to match the implementation:

-    // Return empty data if no mock found
+    // Return error if no mock found
     return fromValue({
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aabf063 and 2e74b41.

⛔ Files ignored due to path filters (1)
  • website/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (44)
  • README.md (2 hunks)
  • website/__tests__/api/circulating_supply.test.ts (1 hunks)
  • website/__tests__/api/market_cap.test.ts (1 hunks)
  • website/__tests__/api/total_supply.test.ts (1 hunks)
  • website/__tests__/components/Button.test.tsx (1 hunks)
  • website/__tests__/components/Input.test.tsx (1 hunks)
  • website/__tests__/components/JobsList.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useArbitrator.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useArbitrators.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorCompletedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorDisputedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorOpenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useCreatorTakenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJob.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobEvents.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobSearch.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useJobsByIds.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useMarketplace.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useReviews.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useSquidStatus.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUser.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUserNotifications.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUsers.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerApplications.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerCompletedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerDisputedJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/subsquid/useWorkerTakenJobs.test.tsx (1 hunks)
  • website/__tests__/hooks/useConfig.test.ts (1 hunks)
  • website/__tests__/hooks/useDimensions.test.tsx (1 hunks)
  • website/__tests__/hooks/useToast.test.ts (1 hunks)
  • website/__tests__/integration/job-creation-flow.test.tsx (1 hunks)
  • website/__tests__/lib/utils.test.ts (1 hunks)
  • website/__tests__/pages/AcceptButton.test.tsx (1 hunks)
  • website/__tests__/pages/ConnectWallet.test.tsx (1 hunks)
  • website/__tests__/pages/DeliverResultButton.test.tsx (1 hunks)
  • website/__tests__/pages/PostJobPage.test.tsx (1 hunks)
  • website/__tests__/pages/TakeJobButton.test.tsx (1 hunks)
  • website/__tests__/setup/mocks/urql.tsx (1 hunks)
  • website/__tests__/setup/test-utils.tsx (1 hunks)
  • website/package.json (1 hunks)
  • website/vitest.config.ts (1 hunks)
  • website/vitest.setup.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website/tests/hooks/subsquid/useCreatorDisputedJobs.test.tsx
🚧 Files skipped from review as they are similar to previous changes (19)
  • website/tests/hooks/subsquid/useSquidStatus.test.tsx
  • website/tests/hooks/subsquid/useJob.test.tsx
  • website/tests/hooks/subsquid/useReviews.test.tsx
  • website/tests/hooks/subsquid/useJobsByIds.test.tsx
  • website/tests/hooks/subsquid/useWorkerCompletedJobs.test.tsx
  • website/tests/hooks/subsquid/useUser.test.tsx
  • website/tests/hooks/subsquid/useJobEvents.test.tsx
  • website/tests/pages/AcceptButton.test.tsx
  • website/tests/hooks/subsquid/useCreatorTakenJobs.test.tsx
  • website/tests/hooks/useToast.test.ts
  • website/tests/hooks/subsquid/useWorkerApplications.test.tsx
  • website/tests/hooks/subsquid/useWorkerDisputedJobs.test.tsx
  • website/tests/hooks/useDimensions.test.tsx
  • website/tests/components/Button.test.tsx
  • website/tests/pages/DeliverResultButton.test.tsx
  • website/tests/api/total_supply.test.ts
  • website/tests/hooks/subsquid/useCreatorOpenJobs.test.tsx
  • website/tests/hooks/subsquid/useUserNotifications.test.tsx
  • website/tests/components/JobsList.test.tsx
🧰 Additional context used
🧬 Code graph analysis (14)
website/__tests__/hooks/subsquid/useArbitrator.test.tsx (3)
website/__tests__/setup/mocks/urql.tsx (1)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATOR_BY_ADDRESS (35-41)
website/src/hooks/subsquid/useArbitrator.tsx (1)
  • useArbitrator (11-38)
website/__tests__/hooks/subsquid/useArbitrators.test.tsx (3)
website/__tests__/setup/mocks/urql.tsx (2)
  • mockArbitrator (101-108)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_ARBITRATORS (27-33)
website/src/hooks/subsquid/useArbitrators.tsx (1)
  • useArbitrators (6-20)
website/__tests__/components/Input.test.tsx (1)
website/src/components/Input.tsx (1)
  • Input (11-89)
website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (3)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS_BY_ADDRESSES (108-114)
website/__tests__/setup/mocks/urql.tsx (1)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/useUsersByAddresses.tsx (1)
  • useUsersByAddresses (13-47)
website/__tests__/hooks/subsquid/useUsers.test.tsx (3)
website/src/hooks/subsquid/queries.ts (1)
  • GET_USERS (92-98)
website/__tests__/setup/mocks/urql.tsx (1)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/useUsers.tsx (1)
  • useUsers (13-27)
website/__tests__/hooks/subsquid/useMarketplace.test.tsx (3)
website/src/hooks/subsquid/queries.ts (1)
  • GET_MARKETPLACES (11-17)
website/__tests__/setup/mocks/urql.tsx (1)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/useMarketplace.tsx (1)
  • useMarketplace (5-19)
website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx (3)
website/__tests__/setup/mocks/urql.tsx (2)
  • mockJob (70-90)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_CLOSED_JOBS (164-170)
website/src/hooks/subsquid/useCreatorClosedJobs.tsx (1)
  • useCreatorClosedJobs (7-24)
website/vitest.setup.ts (1)
website/__tests__/setup/mocks/contracts.ts (1)
  • mockConfig (9-14)
website/__tests__/pages/TakeJobButton.test.tsx (2)
website/__tests__/setup/mocks/urql.tsx (1)
  • mockJob (70-90)
website/__tests__/setup/mocks/apollo.ts (1)
  • mockJob (5-25)
website/__tests__/hooks/useConfig.test.ts (1)
website/src/hooks/useConfig.ts (1)
  • useConfig (5-19)
website/__tests__/hooks/subsquid/useCreatorCompletedJobs.test.tsx (3)
website/__tests__/setup/mocks/urql.tsx (1)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_CREATOR_COMPLETED_JOBS (148-154)
website/src/hooks/subsquid/useCreatorCompletedJobs.tsx (1)
  • useCreatorCompletedJobs (7-24)
website/__tests__/hooks/subsquid/useJobSearch.test.tsx (3)
website/__tests__/setup/mocks/urql.tsx (2)
  • mockJob (70-90)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_JOB_SEARCH (172-190)
website/src/hooks/subsquid/useJobSearch.tsx (1)
  • useJobSearch (10-130)
website/__tests__/hooks/subsquid/useWorkerTakenJobs.test.tsx (2)
website/__tests__/setup/mocks/urql.tsx (2)
  • mockJob (70-90)
  • createUrqlWrapper (61-67)
website/src/hooks/subsquid/queries.ts (1)
  • GET_WORKER_TAKEN_JOBS (207-213)
website/__tests__/lib/utils.test.ts (1)
website/src/lib/utils.ts (9)
  • cn (7-9)
  • formatDate (10-17)
  • absoluteUrl (18-20)
  • EventTextMap (21-90)
  • isImageValid (92-102)
  • shortenText (104-124)
  • convertToSeconds (126-143)
  • getUnitAndValueFromSeconds (145-171)
  • formatTimeLeft (182-191)
🔇 Additional comments (36)
README.md (2)

3-7: LGTM! Badges enhance project visibility.

The badges provide useful at-a-glance information about the license, tech stack versions, test coverage, and PR review activity.


37-39: LGTM! Star history provides useful growth metrics.

The Star History chart is a standard addition that helps track the project's GitHub popularity over time.

website/__tests__/components/Input.test.tsx (5)

1-11: LGTM! Test setup and basic rendering are well-structured.

The imports and initial rendering test provide a solid foundation for the test suite.


13-21: LGTM! User interaction test follows best practices.

Using user-event for typing simulation provides realistic user interaction testing, and the assertion correctly verifies the input value.


23-37: LGTM! Comprehensive type testing.

The tests cover various input types efficiently using rerender, and the date type test ensures proper handling of date-specific inputs.


39-77: LGTM! Thorough state and attribute testing.

The tests comprehensively cover disabled state, custom styling, ref forwarding, event handling, and invalid state. The use of vi.fn() for onChange and React.createRef() for ref testing are appropriate.


79-118: LGTM! Excellent HTML5 attribute coverage.

The tests comprehensively verify support for standard HTML5 input attributes including min/max, required, maxLength, pattern, autoComplete, and autoFocus. The toHaveFocus() assertion for autoFocus is particularly appropriate.

website/vitest.setup.ts (5)

1-25: LGTM! Comprehensive wagmi mock for test environment.

The wagmi mock provides safe defaults for all essential hooks and prevents ESM module resolution issues during testing. The passthrough providers and default hook returns ensure tests can run without real wallet connections.


27-31: LGTM! RainbowKit mock is appropriate for test isolation.

The mock provides passthrough for the RainbowKitProvider and stubs getDefaultConfig, allowing tests to run without full RainbowKit configuration.


33-52: LGTM! Next.js navigation mocks cover essential routing.

The mocks for useRouter, useSearchParams, and usePathname provide safe defaults that allow components using Next.js navigation to render and function in tests without actual routing.


54-86: LGTM! Browser API mocks prevent jsdom compatibility issues.

The mocks for matchMedia, IntersectionObserver, and ResizeObserver provide the minimal implementations needed for jsdom, preventing "not defined" errors when components use these browser-specific APIs.


88-90: LGTM! TextEncoder/TextDecoder shims enable encoding tests.

Adding global TextEncoder and TextDecoder ensures compatibility with code that uses these Web APIs for text encoding, which may not be available by default in the Node.js test environment.

website/vitest.config.ts (3)

1-10: LGTM! Vitest configuration is well-structured for React testing.

The configuration correctly enables the React plugin, global test APIs, jsdom environment, and references the setup file for environment mocks.


11-24: LGTM! Coverage and reporting configuration is comprehensive.

The coverage setup uses the modern v8 provider with multiple output formats (text, lcov, html) and appropriate include/exclude patterns. The junit reporter with output file enables CI integration for test results.


26-31: LGTM! Path aliases improve import ergonomics.

The path aliases for @ (src directory) and @/__tests__ (test utilities) provide cleaner imports and align with common project conventions.

website/__tests__/hooks/subsquid/useCreatorCompletedJobs.test.tsx (2)

1-32: LGTM! Test correctly uses URQL mocks.

The test properly uses createUrqlWrapper for URQL-based testing (addressing the migration from Apollo). The mock structure matches the GET_CREATOR_COMPLETED_JOBS query with correct variable names.


34-46: LGTM! Test case correctly validates hook behavior.

The test invokes the hook with the correct signature (useCreatorCompletedJobs('0xCreator1')) and validates that completed jobs (state: 3) are returned with appropriate loading state. The comment about synchronous mocks is helpful context.

website/__tests__/hooks/subsquid/useMarketplace.test.tsx (2)

1-25: LGTM! Mock setup correctly uses URQL.

The test uses createUrqlWrapper for URQL-based testing (correctly migrated from Apollo). The mock structure matches the GET_MARKETPLACES query and returns a single marketplace in an array, which aligns with the hook implementation that extracts marketplaces[0].


27-38: LGTM! Test validates marketplace stats retrieval.

The test correctly invokes useMarketplace() with no arguments and validates that marketplace statistics are retrieved with the appropriate data structure and loading state.

website/__tests__/hooks/subsquid/useUsersByAddresses.test.tsx (1)

1-36: LGTM! Mock setup uses correct URQL wrapper and variable names.

The test correctly uses createUrqlWrapper for URQL-based testing and properly names the query variable userAddresses (matching the GET_USERS_BY_ADDRESSES query definition). This addresses the issues flagged in previous reviews.

website/__tests__/hooks/subsquid/useWorkerTakenJobs.test.tsx (2)

1-31: LGTM! Mock setup correctly uses URQL with proper variables.

The test uses createUrqlWrapper for URQL-based testing and correctly provides only workerAddress as a variable (matching the GET_WORKER_TAKEN_JOBS query definition). This addresses the issues with extra variables flagged in previous reviews.


33-45: LGTM! Test validates worker taken jobs retrieval.

The test correctly invokes the hook with a string parameter (useWorkerTakenJobs('0xWorker1')) and validates that taken jobs (state: 1) are returned with correct loading state and data structure.

website/__tests__/hooks/subsquid/useArbitrator.test.tsx (4)

6-16: LGTM! Comprehensive mock arbitrator.

The mock arbitrator object includes all necessary fields for testing, including address_, publicKey, fee, settledCount, and refusedCount. The field naming (address_ with underscore) correctly matches the GraphQL schema field name.


18-39: LGTM! Well-structured mock scenarios.

The mock setup covers both success and not-found cases, providing comprehensive test data for the different scenarios tested below.


41-69: LGTM! Proper async testing with clear assertions.

Both test cases correctly use waitFor to handle async state updates and verify the expected behavior for found and not-found scenarios.


71-79: LGTM! Correct handling of empty address case.

The test properly validates the hook's behavior when no address is provided, matching the implementation that immediately returns null data without making a query.

website/__tests__/pages/ConnectWallet.test.tsx (1)

15-15: Test suite is skipped.

The entire test suite uses describe.skip, meaning these tests won't run. If the ConnectWallet component is ready for testing, remove the .skip to enable the tests. If there are known issues preventing test execution, document them in a comment.

Do you want me to help investigate why these tests are skipped, or open an issue to track enabling them?

website/__tests__/pages/PostJobPage.test.tsx (1)

22-22: Test suite is skipped.

The entire test suite uses describe.skip, meaning these tests won't run. Since this tests core job posting functionality, consider prioritizing enabling these tests or documenting the blockers.

Do you want me to help investigate why these tests are skipped, or open an issue to track enabling them?

website/__tests__/api/circulating_supply.test.ts (1)

5-13: LGTM! Functional NextResponse mock.

The mock provides the essential methods (text, json, status, headers) needed for these tests. The implementation correctly simulates the response interface.

website/__tests__/hooks/subsquid/useArbitrators.test.tsx (2)

6-24: Consider field name consistency.

The local mockArbitrator uses feePercentage (line 9) while the shared mock in website/__tests__/setup/mocks/urql.tsx uses fee (line 105). Verify which field name matches the actual GraphQL schema to ensure test accuracy.

Additionally, consider reusing the shared mockArbitrator if the schema allows, to maintain consistency across tests:

import { mockArbitrator } from '../../setup/mocks/urql';

41-67: LGTM! Correct hook invocation and async testing.

The tests now correctly use positional parameters useArbitrators(0, 1000) instead of the previously incorrect object syntax. The async testing with waitFor is properly implemented.

website/__tests__/setup/test-utils.tsx (2)

10-15: LGTM! Minimal but functional mock client.

The mock URQL client provides a good baseline for tests that don't need specific data. Tests requiring custom responses can use createUrqlWrapper from website/__tests__/setup/mocks/urql.tsx instead, which this utility complements nicely.


17-31: LGTM! Well-structured custom render utility.

The custom render function follows testing-library best practices by wrapping components with necessary providers. Re-exporting as render allows tests to import from this file and automatically get the URQL provider, reducing boilerplate.

website/package.json (2)

13-16: LGTM! Well-configured test scripts.

The new test scripts provide good coverage for development workflows:

  • test: Single run for CI
  • test:watch: Interactive development
  • test:coverage: Coverage reporting with output directory

This aligns well with the Vitest configuration added in this PR.


79-79: ```bash
#!/bin/bash

Re-run synchronous API usage checks, including .tsx files

echo "Checking for synchronous cookies() usage in TS/TSX files:"
rg -n -C2 -g '!node_modules/**' -g '.ts' -g '.tsx' '\bcookies()' | grep -v 'await cookies'

echo -e "\nChecking for synchronous headers() usage in TS/TSX files:"
rg -n -C2 -g '!node_modules/**' -g '.ts' -g '.tsx' '\bheaders()' | grep -v 'await headers'

echo -e "\nChecking for synchronous params access in exported route handlers:"
rg -n -C2 -g '!node_modules/**' -g '.ts' -g '.tsx' 'export function [A-Z].*(.*params:' | grep -v '^.*async'

echo -e "\nChecking for deprecated React hooks:"
rg -n -C2 -g '!node_modules/**' -g '.ts' -g '.tsx' 'useFormState'


</blockquote></details>
<details>
<summary>website/__tests__/hooks/subsquid/useUsers.test.tsx (1)</summary><blockquote>

`49-59`: **LGTM!**

The test correctly calls `useUsers(0, 1000)` with positional arguments matching the hook's signature, and properly verifies synchronous mock behavior with URQL.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +1 to +5
import { renderHook, waitFor } from '@testing-library/react';
import useCreatorClosedJobs from '../../../src/hooks/subsquid/useCreatorClosedJobs';
import { GET_CREATOR_CLOSED_JOBS } from '../../../src/hooks/subsquid/queries';
import { createUrqlWrapper } from '../../setup/mocks/urql';

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify query name and filter alignment.

In website/src/hooks/subsquid/queries.ts (lines 163-169), the query is named GetCreatorDisputedJobs but it's exported as GET_CREATOR_CLOSED_JOBS and filters for state_eq: 2 with type__eq:7. Please verify:

  1. Is state 2 the correct value for "closed" jobs (not "disputed")?
  2. Should the query name be updated to match its actual purpose?

Run this script to check the query definition and verify the state values used across the codebase:


🏁 Script executed:

#!/bin/bash
# Check the query definition
echo "=== GET_CREATOR_CLOSED_JOBS query ==="
rg -A 5 "GET_CREATOR_CLOSED_JOBS = gql" website/src/hooks/subsquid/queries.ts

# Find all references to job states to understand the state enum
echo "=== Job state references ==="
rg "state_eq: \d+" website/src/hooks/subsquid/queries.ts

Length of output: 1258


🏁 Script executed:

#!/bin/bash
echo "=== Exported query constants in queries.ts ==="
rg -nP "^export const \w+" website/src/hooks/subsquid/queries.ts

echo "=== Queries mentioning 'disputed' ==="
rg -n "disputed" website/src/hooks/subsquid/queries.ts

Length of output: 1647


Fix GraphQL operation name for closed jobs.
In website/src/hooks/subsquid/queries.ts, GET_CREATOR_CLOSED_JOBS is declared as query GetCreatorDisputedJobs but filters for closed jobs (state_eq: 2). Rename the operation to GetCreatorClosedJobs to align its name with its purpose and avoid conflicts with the disputed jobs query.

🤖 Prompt for AI Agents
In website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx lines 1-5, the
test imports GET_CREATOR_CLOSED_JOBS which in
website/src/hooks/subsquid/queries.ts is defined with the wrong GraphQL
operation name `query GetCreatorDisputedJobs` despite filtering for closed jobs;
update the operation name to `query GetCreatorClosedJobs` in the
GET_CREATOR_CLOSED_JOBS definition so the GraphQL operation name matches its
purpose and avoids conflicts with the disputed jobs query.

Comment on lines +6 to +17
const mockJob = {
id: '1',
state: 4,
title: 'Closed Job',
roles: {
creator: '0xCreator1',
worker: null,
arbitrator: '0xArbitrator',
},
amount: '1000000',
token: '0xUSDC',
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix state value to match query filter.

The mock job has state: 4 (line 8), but the GET_CREATOR_CLOSED_JOBS query filters for state_eq: 2. This mismatch will cause the test to pass with unrealistic data that wouldn't match the actual query results.

Update the mock to match the query's filter:

 const mockJob = {
   id: '1',
-  state: 4,
+  state: 2,
   title: 'Closed Job',
📝 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 mockJob = {
id: '1',
state: 4,
title: 'Closed Job',
roles: {
creator: '0xCreator1',
worker: null,
arbitrator: '0xArbitrator',
},
amount: '1000000',
token: '0xUSDC',
};
const mockJob = {
id: '1',
state: 2,
title: 'Closed Job',
roles: {
creator: '0xCreator1',
worker: null,
arbitrator: '0xArbitrator',
},
amount: '1000000',
token: '0xUSDC',
};
🤖 Prompt for AI Agents
In website/__tests__/hooks/subsquid/useCreatorClosedJobs.test.tsx around lines 6
to 17, the mockJob uses state: 4 but the GET_CREATOR_CLOSED_JOBS query filters
for state_eq: 2; update the mock to use state: 2 so the mocked data matches the
query filter (change state value from 4 to 2) and rerun the test.

useSearchParams: () => new URLSearchParams(),
}));

describe.skip('Job Creation Flow Integration', () => {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Enable the integration test suite.

The entire integration test suite is skipped with describe.skip, preventing these important end-to-end tests from running in CI/CD.

Remove the .skip to enable the tests:

-describe.skip('Job Creation Flow Integration', () => {
+describe('Job Creation Flow Integration', () => {
📝 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
describe.skip('Job Creation Flow Integration', () => {
describe('Job Creation Flow Integration', () => {
🤖 Prompt for AI Agents
In website/__tests__/integration/job-creation-flow.test.tsx around line 34, the
integration test suite is currently disabled using describe.skip which prevents
the tests from running; remove the .skip so the suite is executed (change
describe.skip to describe) and run the test suite locally/CI to ensure no
flakiness or required test updates before committing.

Comment on lines +57 to +58
const PostJobPage = require('@/app/post-job/PostJobPage').default;
render(<PostJobPage />);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace dynamic require with static import.

Using require('@/app/post-job/PostJobPage').default bypasses static analysis and can cause issues with module mocking and tree-shaking. Static imports are more reliable and work better with TypeScript.

Add a static import at the top of the file:

+import PostJobPage from '@/app/post-job/PostJobPage';
+
 /**
+ * Integration Test: Complete Job Creation Flow

Then replace the dynamic requires:

-    const PostJobPage = require('@/app/post-job/PostJobPage').default;
     render(<PostJobPage />);

Apply the same pattern at lines 135 and 163.

📝 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 PostJobPage = require('@/app/post-job/PostJobPage').default;
render(<PostJobPage />);
// At the top of website/__tests__/integration/job-creation-flow.test.tsx
import PostJobPage from '@/app/post-job/PostJobPage';
/**
* Integration Test: Complete Job Creation Flow
* …rest of file header…
*/
// …later in the file, replace the dynamic require:
render(<PostJobPage />);
🤖 Prompt for AI Agents
In website/__tests__/integration/job-creation-flow.test.tsx around lines 57-58
(and also update occurrences at lines 135 and 163), replace the dynamic require
calls with static imports: add top-of-file imports like `import PostJobPage from
'@/app/post-job/PostJobPage';` (and the equivalent static imports for the
modules currently required at lines 135 and 163), then remove the
`require(...).default` usages and use the imported identifiers directly in the
render calls; ensure the import paths match the existing require paths and
update any TypeScript types if necessary.

readContract: vi.fn(),
}));

describe.skip('TakeJobButton', () => {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Enable the test suite.

The entire test suite is skipped with describe.skip. This prevents these tests from running in CI/CD, reducing test coverage for the TakeJobButton component.

Remove the .skip to enable the tests:

-describe.skip('TakeJobButton', () => {
+describe('TakeJobButton', () => {
📝 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
describe.skip('TakeJobButton', () => {
describe('TakeJobButton', () => {
🤖 Prompt for AI Agents
In website/__tests__/pages/TakeJobButton.test.tsx around line 46, the test suite
is currently disabled using describe.skip which prevents tests from running;
remove the ".skip" so the suite reads describe('TakeJobButton', () => { and
ensure any tests inside are not individually skipped so the suite runs in CI/CD.

Comment on lines +14 to +22
const executeQuery = vi.fn((request: any) => {
const mock = mocks.find(
(m) => {
// Compare query by converting to string (handles DocumentNode comparison)
const queryMatch = String(m.query) === String(request.query) || m.query === request.query;
const variablesMatch = JSON.stringify(m.variables || {}) === JSON.stringify(request.variables || {});
return queryMatch && variablesMatch;
}
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Query comparison may fail for complex DocumentNode objects.

Converting GraphQL queries to strings (line 18) for comparison can be unreliable. DocumentNode objects may have different serialization results despite being semantically identical, leading to false negatives in mock matching.

Consider using a more robust comparison approach:

 const executeQuery = vi.fn((request: any) => {
   const mock = mocks.find(
     (m) => {
-      // Compare query by converting to string (handles DocumentNode comparison)
-      const queryMatch = String(m.query) === String(request.query) || m.query === request.query;
+      // Compare queries by their loc.source.body if available (GraphQL DocumentNode)
+      const mockQueryStr = m.query?.loc?.source?.body || String(m.query);
+      const reqQueryStr = request.query?.loc?.source?.body || String(request.query);
+      const queryMatch = mockQueryStr === reqQueryStr;
       const variablesMatch = JSON.stringify(m.variables || {}) === JSON.stringify(request.variables || {});
       return queryMatch && variablesMatch;
     }
   );
📝 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 executeQuery = vi.fn((request: any) => {
const mock = mocks.find(
(m) => {
// Compare query by converting to string (handles DocumentNode comparison)
const queryMatch = String(m.query) === String(request.query) || m.query === request.query;
const variablesMatch = JSON.stringify(m.variables || {}) === JSON.stringify(request.variables || {});
return queryMatch && variablesMatch;
}
);
const executeQuery = vi.fn((request: any) => {
const mock = mocks.find(
(m) => {
// Compare queries by their loc.source.body if available (GraphQL DocumentNode)
const mockQueryStr = m.query?.loc?.source?.body || String(m.query);
const reqQueryStr = request.query?.loc?.source?.body || String(request.query);
const queryMatch = mockQueryStr === reqQueryStr;
const variablesMatch = JSON.stringify(m.variables || {}) === JSON.stringify(request.variables || {});
return queryMatch && variablesMatch;
}
);
🤖 Prompt for AI Agents
In website/__tests__/setup/mocks/urql.tsx around lines 14 to 22, comparing
GraphQL queries by String(m.query) is unreliable for DocumentNode ASTs; instead
normalize both queries before comparing by either importing and using graphql's
print() to serialize both ASTs consistently (compare print(m.query) ===
print(request.query)) or perform a structural AST deep-equality check (e.g.,
lodash.isEqual on m.query and request.query); update the comparison to use one
of these robust approaches and keep the existing variables JSON comparison.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant