Skip to content
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

fix: Screenshot Details Card show twice #3396

Merged
merged 3 commits into from
Dec 8, 2024
Merged

fix: Screenshot Details Card show twice #3396

merged 3 commits into from
Dec 8, 2024

Conversation

Cedric921
Copy link
Contributor

@Cedric921 Cedric921 commented Dec 5, 2024

Description

Please include a summary of the changes and the related issue.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Previous screenshots

Screen.Recording.2024-12-05.at.11.17.54.mov

Current screenshots

Screen.Recording.2024-12-05.at.12.37.38.mov

Summary by CodeRabbit

  • New Features

    • Introduced a new state management for selected screenshots in the ScreenshootPerHour component.
    • Updated modal functionality to display details for the selected screenshot.
  • Bug Fixes

    • Enhanced the ScreenshotDetailsModal to handle optional screenshot data gracefully, preventing errors when data is not available.
  • Style

    • Improved styling for dark mode in the ScreenshotItem component to enhance visual distinction.

These changes improve user experience by ensuring accurate display of screenshot details, enhancing robustness, and providing better visual consistency in dark mode.

Copy link
Contributor

coderabbitai bot commented Dec 5, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/lib/features/activity/components/screenshoots-per-hour.tsx

Oops! Something went wrong! :(

ESLint: 8.46.0

ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.

The config "next/core-web-vitals" was referenced from the config file in "/apps/web/.eslintrc.json".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

Walkthrough

The changes involve modifications to the ScreenshootPerHour, ScreenshotDetailsModal, and ScreenshotItem components. A new state variable selectedElement is introduced in ScreenshootPerHour to manage the currently selected screenshot, along with a new function openScreenModal to handle modal opening. The ScreenshotDetailsModal component's slot prop is made optional, with updates to safely handle cases where it may be undefined. Additionally, ScreenshotItem receives styling updates for dark mode without changes to its logic.

Changes

File Change Summary
apps/web/lib/features/activity/components/screenshoots-per-hour.tsx - Added state variable selectedElement to manage selected ITimerSlot.
- Introduced openScreenModal function using useCallback to handle modal opening. Replaced inline call in onShow prop.
apps/web/lib/features/activity/components/screenshot-details.tsx - Updated slot prop to be optional (slot?: ITimerSlot).
- Implemented optional chaining for property access to prevent runtime errors. Adjusted rendering logic accordingly.
apps/web/lib/features/activity/components/screenshot-item.tsx - Updated class names for dark mode styling without altering component logic or functionality.

Possibly related PRs

Suggested reviewers

  • evereq

Poem

🐇 In the land of screens and time,
A new selection, oh so prime!
With modals opening wide and bright,
Details now are pure delight.
Optional slots, no need to fear,
Each screenshot's story crystal clear! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Cedric921 Cedric921 self-assigned this Dec 5, 2024
@Cedric921 Cedric921 marked this pull request as ready for review December 5, 2024 10:04
Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (3)
apps/web/lib/features/activity/components/screenshoots-per-hour.tsx (1)

Line range hint 49-77: Apply the same fix to ScreenshootPerHourTeam component.

The ScreenshootPerHourTeam component still renders multiple modals (one per iteration). Apply the same fix using selectedElement state to prevent duplicate modals.

 export const ScreenshootPerHourTeam = ({
 	timeSlots,
 	startedAt,
 	stoppedAt
 }: {
 	timeSlots: ITimerSlot[];
 	startedAt: string;
 	stoppedAt: string;
 }) => {
 	const { isOpen, closeModal, openModal } = useModal();
+	const [selectedElement, setSelectedElement] = React.useState<ITimerSlot | null>(null);
+	
+	const openScreenModal = useCallback((el: ITimerSlot) => {
+		setSelectedElement(el);
+		openModal();
+	}, [openModal]);
+	
 	return (
 		<div className="p-4 my-4 rounded-md dark:bg-[#1E2025] border-[0.125rem] bg-light--theme dark:border-[#FFFFFF0D]">
 			<h3 className="px-4">
@@ -65,7 +72,7 @@
 							startTime={el.startedAt}
 							percent={el.percentage}
 							imageUrl={el.screenshots[0]?.thumbUrl}
-							onShow={() => openModal()}
+							onShow={() => openScreenModal(el)}
 							idSlot={el.id}
 							isTeamPage
 						/>
-						<ScreenshotDetailsModal open={isOpen} closeModal={closeModal} slot={el} />
 					</div>
 				))}
+				<ScreenshotDetailsModal open={isOpen} closeModal={closeModal} slot={selectedElement} />
 			</div>
 		</div>
 	);
apps/web/lib/features/activity/components/screenshot-details.tsx (2)

27-28: Optimize optional chaining usage.

When slot is already checked, using optional chaining on its properties is redundant.

-{slot ? new Date(slot?.startedAt).toLocaleTimeString() + '-' +  new Date(slot?.stoppedAt).toLocaleTimeString(): null}
+{slot ? new Date(slot.startedAt).toLocaleTimeString() + '-' + new Date(slot.stoppedAt).toLocaleTimeString() : null}

Line range hint 71-92: Improve stats and status display handling.

The keyboard/mouse stats and status displays need better null handling to prevent displaying incomplete or incorrect information.

-{t('timer.TIMES')} : {slot?.keyboard} {slot?.keyboardPercentage}%
+{t('timer.TIMES')} : {slot ? `${slot.keyboard} ${slot.keyboardPercentage}%` : '-'}

-{t('timer.TIMES')} : {slot?.mouse} {slot?.mousePercentage}%
+{t('timer.TIMES')} : {slot ? `${slot.mouse} ${slot.mousePercentage}%` : '-'}

-{slot?.isActive ? (
+{slot ? (
   slot.isActive ? (
     <span className="bg-green-600 rounded-lg px-2 m-1">{t('timer.ACTIVE')}</span>
   ) : (
     <span className="bg-red-600 rounded-lg px-2 m-1">{t('timer.INACTIVE')}</span>
   )
+) : null}

-{slot?.isArchived ? (
+{slot ? (
   slot.isArchived ? (
     <span className="bg-gray-600 rounded-lg px-2 m-1">{t('timer.ARCHIVED')}</span>
   ) : (
     <span className="bg-blue-600 rounded-lg px-2 m-1">{t('timer.NOT_ARCHIVED')}</span>
   )
+) : null}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 88fc30c and 344551a.

📒 Files selected for processing (2)
  • apps/web/lib/features/activity/components/screenshoots-per-hour.tsx (3 hunks)
  • apps/web/lib/features/activity/components/screenshot-details.tsx (4 hunks)
🔇 Additional comments (1)
apps/web/lib/features/activity/components/screenshoots-per-hour.tsx (1)

20-25: LGTM! Good fix for the duplicate modal issue.

The introduction of selectedElement state and openScreenModal callback effectively addresses the issue of duplicate Screenshot Details Cards by ensuring only one modal instance is rendered and properly managing its state.

@Cedric921 Cedric921 added this to the v0.2.0 milestone Dec 5, 2024
Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (3)
apps/web/lib/features/activity/components/screenshot-details.tsx (3)

27-27: Optimize the time display logic

The current implementation has redundant optional chaining after the null check. Consider extracting the time formatting logic to a reusable utility function.

-{slot ? new Date(slot?.startedAt).toLocaleTimeString() + '-' +  new Date(slot?.stoppedAt).toLocaleTimeString(): null}
+{slot ? `${new Date(slot.startedAt).toLocaleTimeString()} - ${new Date(slot.stoppedAt).toLocaleTimeString()}` : null}

Line range hint 71-92: Consider extracting status displays into separate components

The activity and archive status displays could be extracted into separate components to improve readability and maintainability. Also, consider simplifying the conditional rendering logic.

+const ActivityStatus = ({ isActive }: { isActive?: boolean }) => (
+  <span className={`rounded-lg px-2 m-1 ${isActive ? 'bg-green-600' : 'bg-red-600'}`}>
+    {isActive ? t('timer.ACTIVE') : t('timer.INACTIVE')}
+  </span>
+);

+const ArchiveStatus = ({ isArchived }: { isArchived?: boolean }) => (
+  <span className={`rounded-lg px-2 m-1 ${isArchived ? 'bg-gray-600' : 'bg-blue-600'}`}>
+    {isArchived ? t('timer.ARCHIVED') : t('timer.NOT_ARCHIVED')}
+  </span>
+);

// Replace the existing status displays with:
<p className="rounded-lg px-1 mb-1 text-white">
  <ActivityStatus isActive={slot?.isActive} />
</p>
<p>
  <ArchiveStatus isArchived={slot?.isArchived} />
</p>

Potential issue with required props being passed as optional values

The verification reveals a mismatch between the component's interface requirements and its usage:

  • IScreenShootItem interface shows that idSlot and endTime are required props (no ? modifier)
  • These props are being passed with optional chaining (slot?.id, slot?.stoppedAt)
  • The component uses these values directly in critical operations:
    • endTime is used in new Date(endTime).toLocaleTimeString()
    • idSlot is used in deleteTimeSlots([idSlot])

Either:

  • The interface should be updated to mark these props as optional
  • Or the parent component should ensure these values are defined before rendering ScreenshotItem
🔗 Analysis chain

Line range hint 34-44: Verify ScreenshotItem handles undefined props

Ensure that the ScreenshotItem component properly handles cases where idSlot and endTime are undefined.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check ScreenshotItem component implementation
ast-grep --pattern 'const ScreenshotItem = ({ idSlot, endTime $$$'

Length of output: 68


Script:

#!/bin/bash
# Let's try a different pattern to find the ScreenshotItem component
ast-grep --pattern 'ScreenshotItem = $$$'

# Also search for any file containing ScreenshotItem definition
fd ScreenshotItem

# As backup, let's use ripgrep to find the component definition
rg "ScreenshotItem.*=.*(\{|props)" -A 10

Length of output: 973


Script:

#!/bin/bash
# Let's check the interface definition and any default value handling
rg "interface IScreenShootItem" -A 10

# Let's also check the actual usage of these props in the component
rg "const ScreenshotItem" -A 20 apps/web/lib/features/activity/components/screenshot-item.tsx

# And check how these props are used within the component body
rg "idSlot|endTime" apps/web/lib/features/activity/components/screenshot-item.tsx

Length of output: 1697

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 344551a and 373519e.

📒 Files selected for processing (2)
  • apps/web/lib/features/activity/components/screenshot-details.tsx (3 hunks)
  • apps/web/lib/features/activity/components/screenshot-item.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/lib/features/activity/components/screenshot-item.tsx
🔇 Additional comments (3)
apps/web/lib/features/activity/components/screenshot-details.tsx (3)

23-23: LGTM: Responsive and dark mode styling

The modal styling changes appropriately handle both dark mode and responsive breakpoints.


29-31: ⚠️ Potential issue

Handle undefined progress values

The progress bar and percentage display might show "undefined%" when slot is null. Add proper fallbacks for these values.

-<ProgressBar progress={slot?.percentage + '%'} width={'100%'} />
-<p className="font-semibold py-1">
-  {slot?.percentage} {t('timer.PERCENT_OF_MINUTES')}
-</p>
+<ProgressBar progress={slot ? `${slot.percentage}%` : '0%'} width={'100%'} />
+{slot && (
+  <p className="font-semibold py-1">
+    {slot.percentage} {t('timer.PERCENT_OF_MINUTES')}
+  </p>
+)}

Line range hint 8-16: Verify the optional slot prop handling across the codebase

The change to make slot optional is good for handling cases where no data is available. However, we should ensure all consumers of this component are aware of this breaking change.

Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (4)
apps/web/lib/features/activity/components/screenshot-details.tsx (4)

Line range hint 9-16: Add loading state UI for when slot is undefined.

While making slot optional is good for handling loading states, consider adding a loading indicator or skeleton UI when slot is undefined to improve user experience.

const ScreenshotDetailsModal = ({
	open,
	closeModal,
	slot
}: {
	open: boolean;
	closeModal: () => void;
	slot?: ITimerSlot| null;
}) => {
	const t = useTranslations();
+	if (!slot) {
+		return (
+			<Modal
+				isOpen={open}
+				title="Screenshots detail"
+				closeModal={closeModal}
+				className="bg-white dark:border-[#26272C] dark:bg-[#191a20] dark:border p-4 rounded-lg lg:w-[60vw] xl:w-[50vw] 2xl:w-[40vw]"
+			>
+				<div className="w-full p-4 animate-pulse">
+					<div className="h-6 bg-gray-200 dark:bg-gray-700 rounded w-1/4 mb-4"></div>
+					<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-full mb-4"></div>
+					<div className="h-48 bg-gray-200 dark:bg-gray-700 rounded w-full"></div>
+				</div>
+			</Modal>
+		);
+	}

28-28: Simplify time display logic.

The code uses both a null check and optional chaining, which is redundant. Since we're already checking if slot exists, we can directly access its properties.

-{slot ? new Date(slot?.startedAt).toLocaleTimeString() + '-' +  new Date(slot?.stoppedAt).toLocaleTimeString(): null}
+{slot ? `${new Date(slot.startedAt).toLocaleTimeString()} - ${new Date(slot.stoppedAt).toLocaleTimeString()}` : null}

Line range hint 72-94: Improve metrics display and extract status indicators.

Consider these improvements:

  1. Use nullish coalescing for metrics display
  2. Extract status indicators into a reusable component
+const StatusIndicator = ({ isActive, label }: { isActive: boolean; label: string }) => (
+  <span className={`rounded-lg px-2 m-1 ${isActive ? 'bg-green-600' : 'bg-red-600'}`}>
+    {label}
+  </span>
+);

-{t('timer.TIMES')} : {slot?.keyboard} {slot?.keyboardPercentage}%
+{t('timer.TIMES')} : {slot?.keyboard ?? 0} {slot?.keyboardPercentage ?? 0}%

-{slot?.isActive ? (
-  <span className="bg-green-600 rounded-lg px-2 m-1">{t('timer.ACTIVE')}</span>
-) : (
-  <span className="bg-red-600 rounded-lg px-2 m-1">{t('timer.INACTIVE')}</span>
-)}
+<StatusIndicator 
+  isActive={Boolean(slot?.isActive)} 
+  label={t(slot?.isActive ? 'timer.ACTIVE' : 'timer.INACTIVE')} 
+/>

Potential issue with undefined idSlot in ScreenshotItem

The IScreenShootItem interface requires idSlot as a non-optional string parameter, but it's being passed with optional chaining (slot?.id). This could lead to runtime errors in two scenarios:

  • When deleting screenshots, as deleteTimeSlots([idSlot]) is called with potentially undefined value
  • The interface contract is violated when undefined is passed instead of the required string

Suggested fixes:

  • Add a null check before rendering the ScreenshotItem component
  • Or make idSlot optional in the interface if undefined values should be handled
🔗 Analysis chain

Line range hint 35-44: Verify ScreenshotItem handles undefined slot ID.

The idSlot prop is passed with optional chaining, but we should verify that the ScreenshotItem component can handle undefined values properly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if ScreenshotItem component handles undefined idSlot
ast-grep --pattern 'interface Props {
  $$$
  idSlot: $_
  $$$
}' apps/web/lib/features/activity/components/screenshot-item.tsx

Length of output: 129


Script:

#!/bin/bash
# Let's first check if the file exists and see its content
fd screenshot-item.tsx

# If found, let's examine the component's props and implementation
rg -A 5 "interface|type.*Props" --type typescript

Length of output: 173


Script:

#!/bin/bash
# Let's examine the ScreenshotItem component implementation
cat apps/web/lib/features/activity/components/screenshot-item.tsx

Length of output: 3303


Script:

#!/bin/bash
# Let's check the interface definition for IScreenShootItem
cat apps/web/interfaces/IScreenshoot.ts 2>/dev/null || cat apps/web/lib/interfaces/IScreenshoot.ts 2>/dev/null || rg -l "IScreenShootItem"

Length of output: 214


Script:

#!/bin/bash
# Let's examine the interface definition
cat apps/web/app/interfaces/IScreenshoot.ts

Length of output: 360

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 373519e and 9c1e9df.

📒 Files selected for processing (2)
  • apps/web/lib/features/activity/components/screenshoots-per-hour.tsx (3 hunks)
  • apps/web/lib/features/activity/components/screenshot-details.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/lib/features/activity/components/screenshoots-per-hour.tsx
🔇 Additional comments (2)
apps/web/lib/features/activity/components/screenshot-details.tsx (2)

30-32: ⚠️ Potential issue

Safeguard percentage display.

While the progress bar now handles undefined values, the percentage display still needs protection against undefined values.

<ProgressBar progress={slot ? `${slot.percentage}%` : '0%'} width={'100%'} />
<p className="font-semibold py-1">
-  {slot?.percentage} {t('timer.PERCENT_OF_MINUTES')}
+  {slot?.percentage ? `${slot.percentage} ${t('timer.PERCENT_OF_MINUTES')}` : '0 ' + t('timer.PERCENT_OF_MINUTES')}
</p>

Likely invalid or redundant comment.


102-102: Verify memoization necessity.

While memoization can improve performance, it's only beneficial if the component receives stable props and renders frequently. Please verify that this is the case.

✅ Verification successful

Memoization is justified for this component

The memoization is appropriate here because:

  1. The component receives simple props (open, closeModal, and slot) that are likely stable between renders
  2. The component renders complex UI with multiple child components and data transformations
  3. It's used within a parent component that might re-render frequently due to user interactions
  4. The modal contains expensive operations like date formatting, percentage calculations, and mapping through screenshots

The implementation shows the component is used in a list rendering context (screenshoots-per-hour.tsx), where memoization can prevent unnecessary re-renders of sibling modal instances.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check component usage and prop changes
rg -A 5 "ScreenshotDetailsModal" --type tsx

Length of output: 71


Script:

#!/bin/bash
# Check component usage and prop changes with ripgrep, without file type restriction
rg -A 5 "ScreenshotDetailsModal"

Length of output: 2326


Script:

#!/bin/bash
# Find the file to analyze its props
fd "screenshot-details.tsx" --type f

Length of output: 101


Script:

#!/bin/bash
# If we find the file, let's examine its content to understand the props
cat apps/web/lib/features/activity/components/screenshot-details.tsx

Length of output: 3278

@evereq evereq merged commit 3b7409d into develop Dec 8, 2024
13 checks passed
@evereq evereq deleted the fix/activity-slot branch December 8, 2024 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: Member Profile Page | Slot Card details is opened twice and does not display screenshots
2 participants