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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const api = createApi({
'User_Standup',
'TASK_REQUEST',
'Extension_Requests',
'Logs',
],
/**
* This api has endpoints injected in adjacent files,
Expand Down
41 changes: 41 additions & 0 deletions src/app/services/logsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { api } from './api';

type LogsQueryParams = {
username?: string;
type?: string;
format?: string;
dev?: boolean;
};

export type LogEntry = {
type: string;
timestamp?: string | number;
from?: string | number;
until?: string | number;
Comment on lines +12 to +14
Copy link

Choose a reason for hiding this comment

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

Ambiguous date/time field types category Functionality

Tell me more
What is the issue?

Date/time fields accept both string and number types without validation or normalization, creating ambiguity in how temporal data should be handled.

Why this matters

This will lead to inconsistent date handling throughout the application, potential runtime errors when consuming code expects a specific format, and difficulty in performing date operations like comparisons or formatting.

Suggested change ∙ Feature Preview

Define consistent types for temporal fields. Either use a single type (e.g., ISO string) or create a union with specific formats:

type LogEntry = {
    type: string;
    timestamp?: string; // ISO 8601 format
    from?: string; // ISO 8601 format
    until?: string; // ISO 8601 format
    taskTitle?: string;
};

Or if the API returns mixed formats, add transformation logic in the query to normalize the data.

Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

taskTitle?: string;
};

export type LogsResponse = {
data: LogEntry[];
message?: string;
};

export const logsApi = api.injectEndpoints({
endpoints: (builder) => ({
getLogs: builder.query<LogsResponse, LogsQueryParams>({
query: (params) => ({
url: '/logs',
params: {
username: params.username,
type: params.type,
format: params.format,
dev: params.dev,
},
}),
Comment on lines +26 to +34
Copy link

Choose a reason for hiding this comment

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

Unnecessary parameter spreading category Design

Tell me more
What is the issue?

The query method unnecessarily spreads parameters individually when the entire params object could be passed directly, violating the KISS principle.

Why this matters

Manual parameter spreading creates maintenance overhead as any new parameter would require modifying both the type and the spreading code. This violates DRY and makes the code more prone to errors.

Suggested change ∙ Feature Preview
query: (params) => ({
    url: '/logs',
    params
}),
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

providesTags: ['Logs'],
Comment on lines +26 to +35
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid sending undefined/falsey query params

fetchBaseQuery will serialize params directly; sending undefined/empty values can lead to confusing server behavior. Build the params object conditionally to include only defined keys.

Apply this diff:

-            query: (params) => ({
-                url: '/logs',
-                params: {
-                    username: params.username,
-                    type: params.type,
-                    format: params.format,
-                    dev: params.dev,
-                },
-            }),
+            query: (params) => {
+                const q: Record<string, string | boolean> = {};
+                if (params.username) q.username = params.username;
+                if (params.type) q.type = params.type;
+                if (params.format) q.format = params.format;
+                if (params.dev === true) q.dev = true;
+                return {
+                    url: '/logs',
+                    params: q,
+                };
+            },
📝 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
query: (params) => ({
url: '/logs',
params: {
username: params.username,
type: params.type,
format: params.format,
dev: params.dev,
},
}),
providesTags: ['Logs'],
query: (params) => {
const q: Record<string, string | boolean> = {};
if (params.username) q.username = params.username;
if (params.type) q.type = params.type;
if (params.format) q.format = params.format;
if (params.dev === true) q.dev = true;
return {
url: '/logs',
params: q,
};
},
providesTags: ['Logs'],
🤖 Prompt for AI Agents
In src/app/services/logsApi.ts around lines 26 to 35, the generated query always
includes keys even when params values are undefined/falsey which causes
fetchBaseQuery to serialize unwanted params; change the query builder to
construct the params object conditionally so only keys with defined
(non-undefined) values are included (e.g., build an empty object and add
username/type/format/dev only when params.username !== undefined, etc., or use a
small helper to filter out undefined entries) so the request URL contains only
intended query parameters.

}),
Comment on lines +25 to +36
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Consider narrowing param and payload types

If the backend has known enums (e.g., type: 'REQUEST_CREATED' | ... and format: 'feed' | ...), modeling those as string literal unions will prevent typos at call sites.

🤖 Prompt for AI Agents
In src/app/services/logsApi.ts around lines 25 to 36, the query currently
accepts broad string types for params.type and params.format; narrow these by
defining and using string-literal unions or exported enums for known backend
values (e.g., type: 'REQUEST_CREATED' | 'REQUEST_COMPLETED' | ... and format:
'feed' | 'json' | ...), update the LogsQueryParams type to reference those
unions/enums, adjust the builder.query generic to use the new type, and update
any call sites to import the new enums/unions so callers get compile-time checks
against typos.

}),
overrideExisting: true,
});
Comment on lines +38 to +39
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Drop overrideExisting unless you need to replace existing endpoints

Setting overrideExisting: true can accidentally mask endpoint name collisions from other injectors. Prefer the default false unless you’re intentionally overriding.

Apply this diff:

-    overrideExisting: true,
+    // Prefer the default (false) to avoid masking accidental name collisions
+    overrideExisting: false,
📝 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
overrideExisting: true,
});
// Prefer the default (false) to avoid masking accidental name collisions
overrideExisting: false,
});
🤖 Prompt for AI Agents
In src/app/services/logsApi.ts around lines 38 to 39, the configuration
currently sets overrideExisting: true which can mask endpoint name collisions;
remove the overrideExisting property (or set it to false) so the default
behavior prevents accidental endpoint replacement, then run the injector/tests
to verify no intentional overrides are required and update any callers if a
deliberate override was intended.


export const { useLazyGetLogsQuery } = logsApi;
83 changes: 80 additions & 3 deletions src/components/Calendar/UserSearchField.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
import { useState, useEffect, ChangeEvent, useRef } from 'react';
import { useRouter } from 'next/router';
import classNames from './UserSearchField.module.scss';
import { useGetAllUsersQuery } from '@/app/services/usersApi';
import { useLazyGetLogsQuery } from '@/app/services/logsApi';
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

De-duplicate LogEntry type; import from logsApi instead

Reuse the exported LogEntry type to avoid divergence.

Apply this diff:

-import { useLazyGetLogsQuery } from '@/app/services/logsApi';
+import { useLazyGetLogsQuery, type LogEntry } from '@/app/services/logsApi';

And remove the local duplicate:

-type LogEntry = {
-    type: string;
-    timestamp?: string | number;
-    from?: string | number;
-    until?: string | number;
-    taskTitle?: string;
-};

Also applies to: 8-15

🤖 Prompt for AI Agents
In src/components/Calendar/UserSearchField.tsx around lines 4 to 15, the file
defines a local duplicate LogEntry type; instead import the exported LogEntry
type from '@/app/services/logsApi' (add it to the existing import on line 4) and
remove the local LogEntry definition and any other duplicated type declarations
between lines 8–15 so the component uses the single shared LogEntry type from
logsApi.

import { logs } from '@/constants/calendar';
import { userDataType } from '@/interfaces/user.type';
import { useOutsideAlerter } from '@/hooks/useOutsideAlerter';

type LogEntry = {
type: string;
timestamp?: string | number;
from?: string | number;
until?: string | number;
taskTitle?: string;
};

type SearchFieldProps = {
onSearchTextSubmitted: (user: userDataType | undefined, data: any) => void;
onSearchTextSubmitted: (
user: userDataType | undefined,
data: CalendarData[]
) => void;
loading: boolean;
};

type CalendarData = {
userId: string;
data: {
startTime: number | undefined;
endTime: number | undefined;
status: string;
}[];
};
Comment on lines +26 to +33
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Constrain status to a specific literal

If this component only emits OOO entries, narrow status to 'OOO' to catch accidental values.

Apply this diff:

-    data: {
-        startTime: number | undefined;
-        endTime: number | undefined;
-        status: string;
-    }[];
+    data: Array<{
+        startTime: number | undefined;
+        endTime: number | undefined;
+        status: 'OOO';
+    }>;
📝 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
type CalendarData = {
userId: string;
data: {
startTime: number | undefined;
endTime: number | undefined;
status: string;
}[];
};
type CalendarData = {
userId: string;
data: Array<{
startTime: number | undefined;
endTime: number | undefined;
status: 'OOO';
}>;
};
🤖 Prompt for AI Agents
In src/components/Calendar/UserSearchField.tsx around lines 24 to 31, the
CalendarData type currently allows any string for the status field; constrain it
to the specific literal 'OOO' by replacing the status: string type with status:
'OOO' so TypeScript will catch accidental values—update the type definition
accordingly and run type checks to ensure all usages conform to the narrowed
literal type.


const SearchField = ({ onSearchTextSubmitted, loading }: SearchFieldProps) => {
const router = useRouter();
const isDevMode = router.query.dev === 'true';

const handleOutsideClick = () => {
setDisplayList([]);
};
Expand All @@ -22,13 +47,65 @@ const SearchField = ({ onSearchTextSubmitted, loading }: SearchFieldProps) => {
filterUser(e.target.value);
};

const handleOnSubmit = (e: React.FormEvent) => {
const toMs = (value?: number | string) => {
if (typeof value === 'string') {
const parsed = Date.parse(value);
return isNaN(parsed) ? undefined : parsed;
}
if (typeof value !== 'number') return undefined as unknown as number;
Copy link

Choose a reason for hiding this comment

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

Invalid type casting in toMs function category Error Handling

Tell me more
What is the issue?

The toMs function returns undefined cast as number when the input is not a number, which creates a type inconsistency.

Why this matters

This type casting will cause runtime errors when the returned value is used in numeric operations or comparisons, as undefined cannot be treated as a number.

Suggested change ∙ Feature Preview

Return undefined directly and update the return type to allow undefined:

const toMs = (value?: number | string): number | undefined => {
    if (typeof value === 'string') {
        const parsed = Date.parse(value);
        return isNaN(parsed) ? undefined : parsed;
    }
    if (typeof value !== 'number') return undefined;
    return value >= 1e12 ? value : value * 1000;
};
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

return value >= 1e12 ? value : value * 1000;
};
Comment on lines +50 to +57
Copy link

Choose a reason for hiding this comment

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

Function recreation on every render category Performance

Tell me more
What is the issue?

Timestamp conversion function is defined inside the component causing recreation on every render.

Why this matters

Function recreation on each render cycle wastes memory and CPU cycles, especially problematic when processing arrays of log entries.

Suggested change ∙ Feature Preview

Move the toMs function outside the component or wrap it in useCallback:

const toMs = useCallback((value?: number | string) => {
    if (typeof value === 'string') {
        const parsed = Date.parse(value);
        return isNaN(parsed) ? undefined : parsed;
    }
    if (typeof value !== 'number') return undefined as unknown as number;
    return value >= 1e12 ? value : value * 1000;
}, []);
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +50 to +57
Copy link

Choose a reason for hiding this comment

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

Unexplained Magic Number in Timestamp Conversion category Readability

Tell me more
What is the issue?

The toMs function contains a magic number (1e12) without explanation of its significance in the timestamp conversion logic.

Why this matters

Future developers will need to deduce why this specific threshold was chosen for timestamp conversion, making maintenance more difficult.

Suggested change ∙ Feature Preview
const MILLISECONDS_TIMESTAMP_THRESHOLD = 1e12; // Threshold to differentiate between seconds and milliseconds timestamps

const toMs = (value?: number | string) => {
    if (typeof value === 'string') {
        const parsed = Date.parse(value);
        return isNaN(parsed) ? undefined : parsed;
    }
    if (typeof value !== 'number') return undefined as unknown as number;
    return value >= MILLISECONDS_TIMESTAMP_THRESHOLD ? value : value * 1000;
};
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +50 to +57
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix toMs return type and remove unsafe cast

Returning undefined as unknown as number lies to the type system and can hide bugs. Return number | undefined and use Number.isNaN for clarity.

Apply this diff:

-    const toMs = (value?: number | string) => {
-        if (typeof value === 'string') {
-            const parsed = Date.parse(value);
-            return isNaN(parsed) ? undefined : parsed;
-        }
-        if (typeof value !== 'number') return undefined as unknown as number;
-        return value >= 1e12 ? value : value * 1000;
-    };
+    const toMs = (value?: number | string): number | undefined => {
+        if (typeof value === 'string') {
+            const parsed = Date.parse(value);
+            return Number.isNaN(parsed) ? undefined : parsed;
+        }
+        if (typeof value !== 'number') return undefined;
+        return value >= 1e12 ? value : value * 1000;
+    };
📝 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 toMs = (value?: number | string) => {
if (typeof value === 'string') {
const parsed = Date.parse(value);
return isNaN(parsed) ? undefined : parsed;
}
if (typeof value !== 'number') return undefined as unknown as number;
return value >= 1e12 ? value : value * 1000;
};
const toMs = (value?: number | string): number | undefined => {
if (typeof value === 'string') {
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
if (typeof value !== 'number') return undefined;
return value >= 1e12 ? value : value * 1000;
};
🤖 Prompt for AI Agents
In src/components/Calendar/UserSearchField.tsx around lines 45 to 52, the toMs
function currently lies to TypeScript by returning "undefined as unknown as
number" and uses isNaN; change the function signature to return number |
undefined, remove the unsafe cast, and use Number.isNaN for clarity: when value
is a string parse it and return parsed or undefined; when value is not a number
return undefined; otherwise return value (treating values < 1e12 as seconds and
multiply by 1000). Ensure the function's TypeScript signature and all call sites
accept number | undefined.


const [triggerGetLogs, { isFetching: isLogsFetching }] =
useLazyGetLogsQuery();

const handleOnSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setDisplayList([]);
const user = usersList.find(
(user: userDataType) => user.username === searchText
);
onSearchTextSubmitted(user, data);

if (!user) {
onSearchTextSubmitted(undefined, []);
return;
}

// Feature flag: Use different data sources based on dev mode
if (!isDevMode) {
// Non-dev mode: Use mock data from constants (original behavior)
const userData = data.find((item: any) => item.userId === user.id);
onSearchTextSubmitted(user, userData ? [userData] : []);
return;
}

// Dev mode: Fetch real OOO data from logs API
const logsResult = await triggerGetLogs({
username: user.username || undefined,
Copy link

Choose a reason for hiding this comment

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

Redundant undefined fallback for username category Functionality

Tell me more
What is the issue?

Unnecessary fallback to undefined when user.username is already optional and could be undefined.

Why this matters

This creates confusing logic where an empty string would be converted to undefined, which may not be the intended behavior and could cause API calls to fail unexpectedly.

Suggested change ∙ Feature Preview

Pass the username directly without the unnecessary fallback:

const logsResult = await triggerGetLogs({
    username: user.username,
    type: 'REQUEST_CREATED',
    format: 'feed',
    dev: true,
});
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

type: 'REQUEST_CREATED',
format: 'feed',
dev: true,
});
Comment on lines +83 to +88
Copy link

Choose a reason for hiding this comment

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

Unmaintainable Hard-coded API Parameters category Readability

Tell me more
What is the issue?

Hard-coded string literals 'REQUEST_CREATED' and 'feed' are used directly in the API call without type safety or centralized configuration.

Why this matters

Changes to these values would require searching through code, and typos won't be caught by the compiler.

Suggested change ∙ Feature Preview
const LOG_TYPES = {
    REQUEST_CREATED: 'REQUEST_CREATED'
} as const;

const LOG_FORMATS = {
    FEED: 'feed'
} as const;

const logsResult = await triggerGetLogs({
    username: user.username || undefined,
    type: LOG_TYPES.REQUEST_CREATED,
    format: LOG_FORMATS.FEED,
    dev: true,
});
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.


const logsResponse = logsResult.data;

const oooEntries = (logsResponse?.data || [])
.filter((log: LogEntry) => log && log.type === 'REQUEST_CREATED')
.map((log: LogEntry) => ({
startTime: toMs(log.from),
endTime: toMs(log.until),
status: 'OOO',
}))
.filter((e) => e.startTime && e.endTime);

Comment on lines +92 to +100
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Preserve zero epoch and tighten filtering

Truthiness check drops 0 timestamps. Use nullish checks instead.

Apply this diff:

-            .filter((e) => e.startTime && e.endTime);
+            .filter((e) => e.startTime != null && e.endTime != null);
📝 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 oooEntries = (logsResponse?.data || [])
.filter((log: LogEntry) => log && log.type === 'REQUEST_CREATED')
.map((log: LogEntry) => ({
startTime: toMs(log.from),
endTime: toMs(log.until),
status: 'OOO',
}))
.filter((e) => e.startTime && e.endTime);
const oooEntries = (logsResponse?.data || [])
.filter((log: LogEntry) => log && log.type === 'REQUEST_CREATED')
.map((log: LogEntry) => ({
startTime: toMs(log.from),
endTime: toMs(log.until),
status: 'OOO',
}))
.filter((e) => e.startTime != null && e.endTime != null);
🤖 Prompt for AI Agents
In src/components/Calendar/UserSearchField.tsx around lines 79 to 87, the final
.filter currently uses a truthiness check (e.startTime && e.endTime) which will
drop valid timestamps equal to 0; change the filter to check for null/undefined
explicitly (e.g., e.startTime !== null && e.startTime !== undefined && e.endTime
!== null && e.endTime !== undefined, or the shorter e.startTime != null &&
e.endTime != null) so zero epoch values are preserved.

const mapped = [
{
userId: user.id,
data: oooEntries,
},
];

onSearchTextSubmitted(user, mapped);
};

const { data: userData, isError, isLoading } = useGetAllUsersQuery();
Expand Down
Loading