Files
Doormilexpress_console/src/pages/api/CLAUDE.md

5.7 KiB

CLAUDE.md — src/pages/api/

Rules for editing api.js. This is the central API layer — every page calls into it. The root CLAUDE.md covers project-wide conventions; this file is the scoped rule sheet for the API layer specifically.


1. Function signature patterns

TanStack useQuery / useInfiniteQuery consumers

Destructure from queryKey in the order the call site declared it. The leading _ is the query name and is intentionally discarded.

// Plain query — destructure { queryKey }, skip the [0] name slot
export const fetchorderscount = async ({ queryKey }) => {
  const [, appId, startdate, enddate, currentStatus, tenantid, locationid] = queryKey;
  const url = `${process.env.REACT_APP_URL}/orders/getordersummary/?applocationid=${appId}&...`;
  const response = await axios.get(url);
  return response.data.details;
};

// Infinite query — also receives pageParam (default to 1)
export const fetchOrders = async ({ pageParam = 1, queryKey }) => {
  const [, appId, currentStatus, debouncedSearch, startdate, enddate, rowsPerPage, tenantid, locationid] = queryKey;
  const url = `${process.env.REACT_APP_URL}/orders/tenant/getorders/?applocationid=${appId}&...&pageno=${pageParam}&pagesize=${rowsPerPage}`;
  const response = await axios.get(url);
  return {
    rows: response.data.details,
    nextPage: response.data.details.length === Number(rowsPerPage) ? pageParam + 1 : undefined
  };
};

Hard rules:

  • The query-key array order at the call site MUST match the destructure order here. Re-ordering one without the other silently breaks every caller.
  • Infinite queries return { rows, nextPage }. nextPage is undefined when the page size wasn't filled (signals end-of-stream to getNextPageParam).
  • Some legacy functions return { data, nextPage } instead of { rows, nextPage } (e.g. getallcustomers). Match the existing shape rather than "fixing" it — call sites depend on the field name.

2. Direct positional-argument calls

A few functions take plain positional arguments instead of queryKey — usually when they're invoked from a useMutation or imperatively. Example: getTenants(appId), gettenantlocations(tenantid).

Pick the signature based on how the function is called:

  • Called via useQuery({ queryFn: fn }) → destructure { queryKey }.
  • Called via useQuery({ queryFn: () => fn(arg) }) → take positional args.
  • Called from a mutation or imperatively → take positional args.

3. Base URL selection

Use base When
process.env.REACT_APP_URL Default for ~95% of endpoints
process.env.REACT_APP_URL2 /users/update, /tenants/update, /tenants/update/services, archival /orders/getorders, /partners/getriderlogs
Hardcoded https://routes.workolik.com Bike solver + reconcile-steps + batch efficiency
Hardcoded https://routemate.workolik.com Auto / multi-trip solver
Hardcoded https://jupiter.nearle.app Login + final /deliveries/createdeliveries commit

When adding a new endpoint, check whether the backend actually serves it on URL or URL2 — don't guess. URL2 lives on a separate service.


4. Error handling pattern

try {
  const response = await axios.get(`${process.env.REACT_APP_URL}/...`);
  return response.data.details;   // or .summary, .data, etc — depends on backend shape
} catch (err) {
  const message = err.response?.data?.message || err.message || 'Something went wrong';
  OpenToast(message);
  return null;                    // or return [] / {} — match what the caller expects
}
  • Toast on failure via OpenToast from components/third-party/OpenToast. Don't throw — TanStack Query's onError is rarely wired by callers.
  • Return a sensible empty default (null, [], {}) so the call site's destructuring doesn't crash.
  • Don't console.log(err) AND toast — toast is enough. Some legacy functions do both; new functions should not.

5. When NOT to add to api.js

The user has tolerated a number of pages making direct inline axios.put / axios.post calls for mutations (e.g. Tenants.js calls axios.put('/tenants/update') inline). Match the surrounding file:

  • Adding a new shared GET → put it in api.js.
  • Adding a one-off mutation used in only one page → tolerated inline in that page; doesn't need a new export here.
  • Adding a polling endpoint used by multiple pages → put it here as a named export so the query cache keys are coherent.

6. Response shape quirks

Backend response shapes are inconsistent. Don't assume response.data.details — check what the specific endpoint returns:

Backend field Used by
response.data.details Most list endpoints
response.data.summary getcustomersummary, gettenantsummary, getpricinglist summary calls
response.data.data getRiderPeriodicLogs, getallcustomers infinite-query page payload
response.data.message Mutation success messages (for toast)
response.data.status Boolean success flag — check before reading .details on some endpoints

When unsure, log the response once during dev and pick the matching field.


7. Things that look broken but are intentional

  • const userid = localStorage.getItem('userid'); at module top — read once at module load, intentional for the fetchAppLocations helper. Don't move it inside the function.
  • Some functions take a pageno 0-indexed and others 1-indexed (pageno: pageParam + 1 vs pageno: pageParam). Backend inconsistency — leave it alone unless you confirm the backend side.
  • A few legacy commented-out function bodies are kept above their current implementation as historical reference. Don't delete them in a drive-by edit.