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

feat: unique number into button #393

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

nikshitak
Copy link

@nikshitak nikshitak commented Oct 24, 2024

Added a button that lets users copy the unique course ID. There's a checkmark that pops up indicating that the ID has been successfully copied. Button design follows figma wireframe.

Resolves #359


This change is Reviewable

Copy link

Your pull request title did not conform to conventional commits standards. Our upcoming automated release pipeline will automatically determine
the proper release version based on your pull request title.
Cheat Sheet

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
  • ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit

1 similar comment
Copy link

Your pull request title did not conform to conventional commits standards. Our upcoming automated release pipeline will automatically determine
the proper release version based on your pull request title.
Cheat Sheet

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
  • ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit

@nikshitak nikshitak changed the title Feature/unique number into button feat/unique number into button Oct 24, 2024
Copy link

Your pull request title did not conform to conventional commits standards. Our upcoming automated release pipeline will automatically determine
the proper release version based on your pull request title.
Cheat Sheet

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
  • ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit

@nikshitak nikshitak changed the title feat/unique number into button feat: unique number into button Oct 24, 2024
@Samathingamajig
Copy link
Collaborator

Please include screenshots of before/after your changes

Copy link
Collaborator

@Samathingamajig Samathingamajig left a comment

Choose a reason for hiding this comment

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

Several files (in red) should be reverted to their original state, they shouldn't be changed in this pr.
image

The one orange, pnpm-lock.yaml, and the blue one, ThemeColors.ts, shouldn't change either, and they have their own comments for more details

@@ -6,6 +6,7 @@ export const colors = {
ut: {
burntorange: '#BF5700',
black: '#333F48',
white: '#FFFFFF',
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not needed. White is already provided by unocss as a color, e.g. text-white. To use the white you made here, it w would be text-ut-white, but again, this doesn't need to be here since pure white is just a color and not specific to our design system.

@@ -34,13 +36,13 @@ export default function PopupCourseBlock({
dragHandleProps,
}: PopupCourseBlockProps): JSX.Element {
const [enableCourseStatusChips, setEnableCourseStatusChips] = useState<boolean>(false);
const [isCopied, setIsCopied] = useState<boolean>(false); // Add state to track if copied
Copy link
Collaborator

Choose a reason for hiding this comment

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

the comment here is unnecessary, isCopied with useState<boolean> is clear enough 👍

className='bg-transparent px-2 py-0.25 text-white btn'
color={colors.secondaryColor}
onClick={handleCopy}
style={{ display: 'flex', backgroundColor: colors.secondaryColor, color: 'text-white' }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

few things here:

  • Unless there's something I'm not seeing, display: 'flex' here should just be the flex class, instead of in the style
  • 'text-white' is not a valid CSS color, it should be just 'white' if you want white. There is a class called text-white which would work here, but [see next point]
  • I think that the text color should be based on the contrast compared to the secondary color, not always white. @IsaDavRod and @Razboy20 might have more info on if that's necessary. It would be something like the line above const fontColor = pickFontColor(colors.primaryColor); but for the secondary color

using the backgroundColor: colors.secondaryColor in style makes sense though, since there aren't classes for those 👍

Copy link
Author

Choose a reason for hiding this comment

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

Screenshot 2024-10-26 at 1 33 50 PM

That's the error I'm getting when I'm trying to set color to fontColor

pnpm-lock.yaml Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

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

This file shouldn't change, since you didn't install any new packages for this. You might be using an outdated version of pnpm?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This file shouldn't change.

.vscode/launch.json Outdated Show resolved Hide resolved
.vscode/settings.json Outdated Show resolved Hide resolved
LICENSE.md Outdated Show resolved Hide resolved
chromatic.config.json Outdated Show resolved Hide resolved
Copy link
Collaborator

@doprz doprz left a comment

Choose a reason for hiding this comment

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

Let's revert back the files that don't require/shouldn't be changed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This file shouldn't change as your PR didn't need changes here. Are you formatting via pnpm run prettier:fix, manually, or another way?

Copy link
Author

Choose a reason for hiding this comment

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

I think it seems to be auto formatting? I checked my settings and turned the option that I thought was causing the issue off, but it still seems to be auto formatting. What I ended up doing is just copy paste the files that changed from the main branch.

@nikshitak
Copy link
Author

Before After
Screenshot 2024-10-25 at 7 43 34 PM Screenshot 2024-10-25 at 7 44 56 PM

Comment on lines 88 to 94
<div
onClick={handleClick}
className={clsx(
'h-full w-full inline-flex items-center justify-center gap-1 rounded pr-3 focusable cursor-pointer text-left',
className
)}
>
Copy link
Member

Choose a reason for hiding this comment

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

Rather than making a new div here, the onClick should stay where it originally was.

Comment on lines 63 to 67
const handleCopy = () => {
navigator.clipboard.writeText(formattedUniqueId);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 1000);
};
Copy link
Member

Choose a reason for hiding this comment

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

an e: MouseEventshould be accepted as the first argument, and e.preventDefault() should be called, as to not also open a background calendar tab when clicking on this button.

(will happen when the other PR comment is resolved)

const handleCopy = () => {
navigator.clipboard.writeText(formattedUniqueId);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 1000);
Copy link
Member

Choose a reason for hiding this comment

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

If you copy the text twice, the previous timeout isn't cancelled, thus the check icon can disappear faster than expected. Rather, a better methodology would be to debounce when the copy state is set to false. (Can probably be done by having the timeout id (returned by setTimeout) be stored in isCopied (perhaps renamed to copyTimeoutId)—it should be set to undefined when it is not active, and to an id when it is.

attempt to clearTimeout(timeoutId), then setTimeoutId(setTImeout(...)). or similar.

Feel free to ping on discord for advice :)

@IsaDavRod IsaDavRod self-requested a review October 27, 2024 21:46
@nikshitak nikshitak requested a review from Razboy20 October 29, 2024 16:31
src/pages/background/background.ts Outdated Show resolved Hide resolved
src/shared/util/updateBadgeText.ts Outdated Show resolved Hide resolved
@Samathingamajig Samathingamajig force-pushed the feature/unique-number-into-button branch from 82c75e6 to 79e283b Compare November 2, 2024 04:13
const formattedUniqueId = course.uniqueId.toString().padStart(5, '0');
const [copyTimeoutId, setCopyTimeoutId] = useState<NodeJS.Timeout | undefined>(undefined);
Copy link
Collaborator

Choose a reason for hiding this comment

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

copyTimeoutId should be a ref (useRef), not a useState, since setState calls are queued until the next render. not doing so could lead to issues when a user clicks multiple times in the same render (aside: does that even matter 🤔)

https://www.freecodecamp.org/news/react-state-vs-ref-differences-and-use-cases/#heading-asynchronous-updates

edit: I would store whether we're currently waiting in another state, and the timeout id in a ref


const handleClick = async () => {
await background.switchToCalendarTab({ uniqueId: course.uniqueId });
window.close();
};

const handleCopy = (event: React.MouseEvent<HTMLElement>) => {
if (copyTimeoutId) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

check for copyTimeoutId !== undefined, since

  1. It's technically possible for the timeout id to be 0
  2. You initialize it to undefined
  3. You check for undefined later


<button
className='flex bg-transparent px-2 py-0.25 text-white btn'
color={colors.secondaryColor}
Copy link
Collaborator

Choose a reason for hiding this comment

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

you set backgroundColor and the text color in the style prop, what's the point of this color prop?

@@ -91,6 +108,20 @@ export default function PopupCourseBlock({
<StatusIcon status={course.status} className='h-5 w-5' />
</div>
)}

<button
className='flex bg-transparent px-2 py-0.25 text-white btn'
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is text-white (applies color: #FFFFFF via CSS) here, when you set the text color in the style prop? (text-white, being a class, is completely overridden by color: buttonColor, since style has greater precedence than class[Name])

Copy link
Member

@IsaDavRod IsaDavRod left a comment

Choose a reason for hiding this comment

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

  • Please address Sam's comment about timeout (if you spam click the button, the checkmark will show for a longer time after the last click)
  • Can the minimum height of the course block's div be 50px?
  • Can the height of the unique number copy button be 30px?
  • It looks like this PR disables some functionality too. When the user clicks the course block in the main popup, it should open the Calendar view and the respective injected cc popup. See prod build as an example.

Copy link
Collaborator

@doprz doprz left a comment

Choose a reason for hiding this comment

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

Please review previous comments and fix the merge conflict.

@DereC4 DereC4 added this to the v2.1.0 milestone Nov 17, 2024
@nikshitak
Copy link
Author

I looked at the Chromatic error and it seemed like the error was stemming from the CourseCatalogInjectedPopup component, but I don't think anything in PopupCourseBlock.tsx has any elements from CourseCatalogInjectedPopup and I haven't modified CourseCatalogInjectedPopup besides pulling from the main branch.

@DereC4 DereC4 requested review from IsaDavRod and doprz November 19, 2024 21:34
>
<div
style={{
backgroundColor: colors.secondaryColor,
}}
className='flex items-center self-stretch rounded rounded-r-0 cursor-move!'
{...dragHandleProps}
onClick={handleClick}
Copy link
Collaborator

Choose a reason for hiding this comment

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

this handleClick was moved to the wrong place, you should be able to click on the PopupCourseBlock and be taken to the calendar to that specific course, with the exception being a click on the unique button

@@ -96,6 +114,19 @@ export default function PopupCourseBlock({
<StatusIcon status={course.status} className='h-5 w-5' />
</div>
)}

<button
className='flex bg-transparent px-2 py-0.25 text-white btn'
Copy link
Collaborator

Choose a reason for hiding this comment

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

what is the intention of the bg-transparent here?

@@ -96,6 +114,19 @@ export default function PopupCourseBlock({
<StatusIcon status={course.status} className='h-5 w-5' />
</div>
)}

<button
className='flex bg-transparent px-2 py-0.25 text-white btn'
Copy link
Collaborator

Choose a reason for hiding this comment

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

the buttons are too large compared to the height of the PopupCourseBlock itself

Current:

image

Desired:

image

Comment on lines +68 to +80
if (copyWait !== undefined) {
clearTimeout(copyWait);
}

event.preventDefault();
navigator.clipboard.writeText(formattedUniqueId);
copyTimeoutIdRef.current += 250;

const newTimeoutId = setTimeout(() => {
setCopyWait(undefined);
}, copyTimeoutIdRef.current);
setCopyWait(newTimeoutId);
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

this makes it so that each subsequent click makes the checkmark show for 250 more milliseconds

when I said to use a ref, I meant use a ref to hold the timeout id, I meant something like

const [showCopyIcon, setShowCopyIcon] = useState<boolean>(false);
const copyTimeoutRef = useRef<number | undefined>(undefined);

// ...

const handleCopy = (event: React.MouseEvent<HTMLElement>) {
    if (copyTimeoutRef.current !== undefined) {
        clearTimeout(copyTimeoutRef.current);
    }

    event.preventDefault();
    navigator.clipboard.writeText(formattedUniqueId);
    showCopyIcon(true);

    copyTimeoutRef.current = window.setTimeout(() => {
        showCopyIcon(false);
    }, 750);
};

probably should bring in a react-friendly debouncing function instead of writing this from scratch, though, since there are most likely other places that will need debouncing and it's easy to get wrong

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.

Turn the Unique Number into a mini button to copy the #.
6 participants