-
Notifications
You must be signed in to change notification settings - Fork 167
Feature : Show Active tasks on calendar #1376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Summary by CodeRabbit
WalkthroughAdds a logs API service with a paginated getLogs endpoint and corresponding hooks. Updates calendar page to support a dev query param flow that fetches logs, aggregates per-date activity, and augments day click details with titles and optional GitHub links. Adds a router read in UserSearchField. Styles ACTIVE days in the calendar. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CalendarPage as Calendar Page
participant LogsAPI as logsApi (RTK Query)
participant Backend as Backend /logs
Note over User,CalendarPage: Dev mode via ?dev=true
User->>CalendarPage: Submit search (username)
alt dev mode
rect rgb(230,245,255)
CalendarPage->>LogsAPI: triggerGetLogs({ type, format, page/size } or next/prev)
LogsAPI->>Backend: GET /logs or GET {next|prev URL}
Backend-->>LogsAPI: { logs, next, prev }
LogsAPI-->>CalendarPage: LogsResponse
CalendarPage->>CalendarPage: Aggregate per-date classes/titles/links
opt has next and within limit
CalendarPage->>LogsAPI: triggerGetLogs({ next })
LogsAPI->>Backend: GET next
Backend-->>LogsAPI: LogsResponse
LogsAPI-->>CalendarPage: LogsResponse
CalendarPage->>CalendarPage: Merge aggregates
end
end
CalendarPage-->>User: Updated calendar with titles/links
else non-dev
CalendarPage->>CalendarPage: Existing processData flow
CalendarPage-->>User: Standard calendar update
end
sequenceDiagram
autonumber
participant Calendar as Calendar Page
participant LogsAPI as logsApi
participant Backend as Backend /logs
Note over Calendar,Backend: Cursor navigation
alt Use explicit cursor
Calendar->>LogsAPI: getLogs({ next|prev })
LogsAPI->>Backend: GET full cursor URL
else Build query
Calendar->>LogsAPI: getLogs({ dev, type, format, page, size })
LogsAPI->>Backend: GET /logs?dev=&type=&format=&page=&size=
end
Backend-->>LogsAPI: { logs, next, prev }
LogsAPI-->>Calendar: LogsResponse
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review by Korbit AI
Korbit automatically attempts to detect when you fix issues in new commits.
| Category | Issue | Status |
|---|---|---|
| Unconstrained string parameters ▹ view | ||
| Unclear timestamp conversion logic ▹ view | ||
| Unused dev variable extracted from router query ▹ view | ✅ Fix detected | |
| Unsafe default for development flag ▹ view | ✅ Fix detected | |
| Complex function needs decomposition ▹ view | ✅ Fix detected | |
| Ambiguous log data properties in response type ▹ view | ✅ Fix detected | |
| Inefficient pagination filtering ▹ view | ✅ Fix detected |
Files scanned
| File Path | Reviewed |
|---|---|
| src/app/services/logsApi.ts | ✅ |
| src/components/Calendar/UserSearchField.tsx | ✅ |
| src/pages/calendar/index.tsx | ✅ |
Explore our documentation to understand the languages and file types we support and the files we ignore.
Check out our docs on how you can make Korbit work best for you and your team.
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
src/app/services/logsApi.ts(1 hunks)src/components/Calendar/UserSearchField.tsx(2 hunks)src/pages/calendar/index.tsx(3 hunks)src/styles/calendar.scss(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/pages/calendar/index.tsx (4)
__tests__/Unit/Components/Tasks/TaskDetails.test.tsx (1)
useRouter(706-713)src/utils/userStatusCalendar.ts (1)
processData(41-71)src/constants/calendar.ts (1)
MONTHS(54-67)src/constants/url.ts (1)
TASKS_URL(26-26)
src/app/services/logsApi.ts (1)
src/app/services/api.ts (1)
api(9-37)
src/components/Calendar/UserSearchField.tsx (1)
__tests__/Unit/Components/Tasks/TaskDetails.test.tsx (1)
useRouter(706-713)
🔇 Additional comments (1)
src/styles/calendar.scss (1)
16-19: Contrast ratio 7.58:1 meets WCAG AAA
__tests__/Unit/Components/ExtensionRequest/ExtensionStatusModal.test.tsx
Show resolved
Hide resolved
|
@RishiChaubey31 in issue ticket you have mentioned PR link can you fix that |
__tests__/Unit/Components/ExtensionRequest/ExtensionStatusModal.test.tsx
Show resolved
Hide resolved
src/pages/calendar/index.tsx
Outdated
| const processTaskDetails = (userLogs: TLogEntry[]) => { | ||
| const classByDate: Record<number, string> = {}; | ||
| const titleByDate: Record<number, string> = {}; | ||
| const taskDataByDate: Record< | ||
| number, | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- please move this function out of this component , either create an utils/helper file or define it top of the component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved it to utils
src/pages/calendar/index.tsx
Outdated
| if (processedData[1]?.[value.getTime()]) { | ||
| const taskData = taskDataByDate[value.getTime()]; | ||
| if (taskData) { | ||
| const startDate = getDateInString(new Date(taskData.startedOn)); | ||
| const endDate = taskData.endsOn | ||
| ? getDateInString(new Date(taskData.endsOn * 1000)) | ||
| : 'Not specified'; | ||
| const taskLink = `https://status.realdevsquad.com/tasks/${taskData.taskId}`; | ||
|
|
||
| setMessage( | ||
| <div> | ||
| <p> | ||
| {`${selectedUser.username} is ACTIVE on ${dateStr}`} | ||
| </p> | ||
| <ul> | ||
| <li>Task: {taskData.taskTitle}</li> | ||
| <li>Start Date: {startDate}</li> | ||
| <li>End Date: {endDate}</li> | ||
| <li> | ||
| Link:{' '} | ||
| <a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- we can also make this any utils function that return the jsx element so something like this
export const generateDayClickMessage = (
date: Date,
selectedUser: TUser,
processedData: TProcessedData,
taskDataByDate: Record<number, TaskData>
): string | JSX.Element => {
return (
<span>
{`${selectedUser.username} is ACTIVE on ${dateStr} having task with title - ${title}`}
</span>
);
};
src/pages/calendar/index.tsx
Outdated
| const [processedData, setProcessedData] = useState<any>( | ||
| processData(selectedUser ? selectedUser.id : null, []) | ||
| ); | ||
| const [selectedUser, setSelectedUser] = useState<TUser | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- we can use query param to store the username rather than using the useState that why on page refresh we don't lost the data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for this idea ..... really nice one
src/pages/calendar/index.tsx
Outdated
| Record< | ||
| number, | ||
| { | ||
| taskId: string; | ||
| taskTitle: string; | ||
| startedOn: number; | ||
| endsOn?: number; | ||
| } | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- please define its type and use it here
src/pages/calendar/index.tsx
Outdated
|
|
||
| const [message, setMessage]: any = useState(null); | ||
| const [loading, setLoading]: any = useState(false); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put a comment here explaining why any is needed here
src/pages/calendar/index.tsx
Outdated
| > | ||
| >({}); | ||
| const [message, setMessage] = useState<string | JSX.Element | null>(null); | ||
| const [loading, setLoading] = useState<boolean>(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const [loading, setLoading] = useState<boolean>(false); | |
| const [isLoading, setIsLoading] = useState<boolean>(false); |
src/pages/calendar/index.tsx
Outdated
| const logDate = new Date(timestamp); | ||
|
|
||
| if (!isNaN(logDate.getTime())) { | ||
| const ts = new Date( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- please better variable name
src/pages/calendar/index.tsx
Outdated
| }; | ||
|
|
||
| const processTaskDetails = (userLogs: TLogEntry[]) => { | ||
| const classByDate: Record<number, string> = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
define type for this one also
src/pages/calendar/index.tsx
Outdated
| if (dev) { | ||
| setLoading(true); | ||
| try { | ||
| const userLogs = await fetchUserLogs(user.username); | ||
| if (!userLogs.length) { | ||
| setProcessedData([{}, {}]); | ||
| setMessage(`No logs found for ${user.username}`); | ||
| return; | ||
| } | ||
| const { classByDate, titleByDate, taskDataByDate } = | ||
| processTaskDetails(userLogs); | ||
| setProcessedData([classByDate, titleByDate]); | ||
| setTaskDataByDate(taskDataByDate); | ||
| setMessage(null); | ||
| } catch (e) { | ||
| setMessage('Unable to fetch logs right now.'); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| } else { | ||
| setProcessedData( | ||
| processData(user.id || null, data as []) as TProcessedData | ||
| ); | ||
| setMessage(null); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use inversion here to avoid the else block
eg:
if(!dev){
// else block logic
return;
}
// remaining logic
src/pages/calendar/index.tsx
Outdated
|
|
||
| const [message, setMessage]: any = useState(null); | ||
| const [loading, setLoading]: any = useState(false); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put a comment here explaining why any is needed here
src/pages/calendar/index.tsx
Outdated
| } | ||
| > | ||
| >({}); | ||
| const [message, setMessage] = useState<string | JSX.Element | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of using both string and JSX.Element can we just use JSX format for string messages?
this way we only have to handle for JSX and null case
src/pages/calendar/index.tsx
Outdated
| setMessage( | ||
| <span> | ||
| {`${selectedUser.username} is ACTIVE on ${dateStr} having task with title - ${title}`} | ||
| </span> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for IDLE we are sending the same message without span tag, kindly refactor to make it consistent
refer to comment above and use either of string or JSX for all
src/pages/calendar/index.tsx
Outdated
| userLogs.forEach((log: TLogEntry) => { | ||
| if (log.type === 'task' && log.taskId && log.taskTitle) { | ||
| const timestamp = log.timestamp * 1000; | ||
| const logDate = new Date(timestamp); | ||
|
|
||
| if (!isNaN(logDate.getTime())) { | ||
| const ts = new Date( | ||
| logDate.getFullYear(), | ||
| logDate.getMonth(), | ||
| logDate.getDate() | ||
| ).getTime(); | ||
|
|
||
| classByDate[ts] = 'ACTIVE'; | ||
| titleByDate[ts] = log.taskTitle; | ||
| taskDataByDate[ts] = { | ||
| taskId: log.taskId, | ||
| taskTitle: log.taskTitle, | ||
| startedOn: timestamp, | ||
| endsOn: log.endsOn, | ||
| }; | ||
|
|
||
| if (log.endsOn) { | ||
| const endDate = new Date(log.endsOn * 1000); | ||
| const cursor = new Date(ts); | ||
| const endDay = new Date( | ||
| endDate.getFullYear(), | ||
| endDate.getMonth(), | ||
| endDate.getDate() | ||
| ); | ||
|
|
||
| while (cursor.getTime() <= endDay.getTime()) { | ||
| classByDate[cursor.getTime()] = 'ACTIVE'; | ||
| titleByDate[cursor.getTime()] = log.taskTitle; | ||
| taskDataByDate[cursor.getTime()] = { | ||
| taskId: log.taskId, | ||
| taskTitle: log.taskTitle, | ||
| startedOn: timestamp, | ||
| endsOn: log.endsOn, | ||
| }; | ||
| cursor.setDate(cursor.getDate() + 1); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please refactor this, and avoid nesting after 2 layers
| const handleDateChange = (value: any) => { | ||
| if (value instanceof Date) onDateChange(value); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The any type is used because react-calendar's onChange can return multiple types, but the code only needs to handle the Date case, so using any with a type guard is a pragmatic solution that avoids the complexity of handling the full union type.
Date: 16-10-2025
Developer Name: Rishi Chaubey
Issue Ticket Number
Description
Currently, our dashboard site has an Activity Feed powered by the Logs API that tracks and displays user activities.
On the status site, we already have a calendar component with a user search option (by username), but it is non-functional.
The goal of this task is to integrate the relevant APIs with the calendar so that when a username is entered, the calendar dynamically displays the user’s activities in a structured and visually intuitive way.
Documentation Updated?
Under Feature Flag
Database Changes
Breaking Changes
Development Tested?
Screenshots
Screenshot 1
Screen.Recording.2025-10-24.020126.mp4
Test Coverage
Test will be in next pr updating the coverage soon !
Screenshot 1
Additional Notes
Description by Korbit AI
What change is being made?
Implement feature to show active tasks on calendar by integrating logs fetching, building per-date activity mappings, and linking GitHub issues when available. Add a development flow that fetches task logs, derives active date ranges from task details, and displays links in calendar messages. Also enhance the calendar page to optionally use this dev flow when the dev query parameter is true.
Why are these changes being made?
To display active task periods directly on the calendar and provide quick access to related GitHub issues during development, while preserving existing behavior for non-dev usage. This enables a richer, interactive calendar experience with minimal disruption to the default flow.