Skip to content

Conversation

@vas3a
Copy link
Collaborator

@vas3a vas3a commented Oct 16, 2025

Related JIRA Ticket:

https://topcoder.atlassian.net/browse/

What's in this PR?

- name: TC AI PR Reviewer
uses: topcoder-platform/tc-ai-pr-reviewer@prompt-update
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The GITHUB_TOKEN is there by default so you just need to keep it like it is and not necessarily need to add it as secret as it will throw an error. [More Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret)

Choose a reason for hiding this comment

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

The comment about the GITHUB_TOKEN is informative but could be misleading if it suggests that no action is needed. Consider rephrasing to clarify that the token is automatically provided by GitHub Actions and does not need to be manually added as a secret.

with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The GITHUB_TOKEN is there by default so you just need to keep it like it is and not necessarily need to add it as secret as it will throw an error. [More Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret)
LAB45_API_KEY: ${{ secrets.LAB45_API_KEY }}
exclude: '**/*.json, **/*.md, **/*.jpg, **/*.png, **/*.jpeg, **/*.bmp, **/*.webp' # Optional: exclude patterns separated by commas

Choose a reason for hiding this comment

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

The exclude pattern is optional, but it might be beneficial to ensure that it aligns with the project's requirements. Double-check that the patterns listed here are indeed the ones you want to exclude from the AI PR review process.

- name: TC AI PR Reviewer
uses: topcoder-platform/tc-ai-pr-reviewer@prompt-update
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The GITHUB_TOKEN is there by default so you just need to keep it like it is and not necessarily need to add it as secret as it will throw an error. [More Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret)

Choose a reason for hiding this comment

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

[💡 readability]
The comment about the GITHUB_TOKEN is informative but could be misleading. It suggests that adding the token as a secret will throw an error, which might not be accurate. Consider clarifying that the token is automatically provided by GitHub Actions and does not need to be manually added as a secret.


// eslint-disable-next-line complexity
export const ChallengeDetailsPage: FC<Props> = (props: Props) => {
const { showBannerNotification, removeNotification }: NotificationContextType = useNotification()

Choose a reason for hiding this comment

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

[💡 maintainability]
The destructuring of useNotification() into showBannerNotification and removeNotification is correct, but ensure that these functions are used within the component. If they are not used, consider removing the destructuring to avoid unnecessary code.


// eslint-disable-next-line complexity
export const ChallengeDetailsPage: FC<Props> = (props: Props) => {
const { showBannerNotification, removeNotification }: NotificationContextType = useNotification()

Choose a reason for hiding this comment

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

The destructuring of NotificationContextType seems unnecessary here. You can directly use const { showBannerNotification, removeNotification } = useNotification(); without specifying the type, as TypeScript can infer it.

id: 'ai-review-scores-warning',
message: `AI Review Scores are advisory only to provide immediate,
educational, and actionable feedback to members.
AI Review Scores are not influence winner selection.`,

Choose a reason for hiding this comment

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

[❗❗ correctness]
The message string contains a grammatical error: 'AI Review Scores are not influence winner selection.' should be corrected to 'AI Review Scores do not influence winner selection.'

educational, and actionable feedback to members.
AI Review Scores are not influence winner selection.`,
})
return () => notification && removeNotification(notification.id)

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider adding error handling for removeNotification(notification.id) to ensure that any issues during the removal process do not cause unintended side effects.

id: 'ai-review-scores-warning',
message: `AI Review Scores are advisory only to provide immediate,
educational, and actionable feedback to members.
AI Review Scores are not influence winner selection.`,

Choose a reason for hiding this comment

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

Typographical error in the message: 'AI Review Scores are not influence winner selection.' should be 'AI Review Scores do not influence winner selection.'

educational, and actionable feedback to members.
AI Review Scores are not influence winner selection.`,
})
return () => notification && removeNotification(notification.id)

Choose a reason for hiding this comment

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

Consider checking if showBannerNotification is defined before calling it to prevent potential runtime errors.


const profileContext: Context<ProfileContextData> = createContext(defaultProfileContextData)

export const useProfileContext = (): ProfileContextData => useContext(profileContext)

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider adding error handling for cases where useProfileContext is called outside of a ProfileContext.Provider. This can help prevent runtime errors and improve developer experience by providing a clear error message.

return (
<div className={styles.wrap}>
{notifications.map(n => (
<Notification key={n.id} notification={n} onClose={removeNotification} />

Choose a reason for hiding this comment

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

[💡 readability]
Consider using a more descriptive name for the variable n in the map function to improve readability. For example, notification would make the code clearer.

return (
<div className={styles.wrap}>
{notifications.map(n => (
<Notification key={n.id} notification={n} onClose={removeNotification} />

Choose a reason for hiding this comment

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

Consider renaming the variable n to something more descriptive, such as notification, to improve code readability.

children: ReactNode,
}> = props => {
const profileCtx = useProfileContext()
const uuid = profileCtx.profile?.userId ?? 'annon'

Choose a reason for hiding this comment

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

[⚠️ correctness]
Using a default user ID of 'annon' might lead to potential issues if multiple anonymous users trigger notifications simultaneously. Consider using a more unique identifier for anonymous users to avoid ID collisions.

setNotifications(prev => [...prev, newNotification])

if (duration > 0) {
setTimeout(() => removeNotification(id), duration)

Choose a reason for hiding this comment

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

[⚠️ performance]
The setTimeout function does not clear the timeout when the component unmounts, which could lead to memory leaks if the component is unmounted before the timeout completes. Consider storing the timeout ID and clearing it in a useEffect cleanup function.


const notify = useCallback(
(message: NotifyPayload, type: NotificationType = 'info', duration = 3000) => {
const id = `${uuid}[${typeof message === 'string' ? message : message.id}]`

Choose a reason for hiding this comment

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

The id generation logic here uses the message as part of the ID, which could lead to potential collisions if the same message is used multiple times. Consider using a more unique identifier, such as a timestamp or a UUID, to ensure uniqueness.

setNotifications(prev => [...prev, newNotification])

if (duration > 0) {
setTimeout(() => removeNotification(id), duration)

Choose a reason for hiding this comment

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

The setTimeout function here does not clear the timeout if the component unmounts before the duration ends. This could lead to memory leaks. Consider storing the timeout ID and clearing it in a useEffect cleanup function.

const lsKeyPrefix = 'notificationDismissed'

export const wasDismissed = (id: string): boolean => (
(localStorage.getItem(`${lsKeyPrefix}[${id}]`)) !== null

Choose a reason for hiding this comment

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

[❗❗ correctness]
Consider handling potential exceptions from localStorage.getItem. If localStorage is unavailable or disabled, this could throw an error, impacting the application's stability.

)

export const dismiss = (id: string): void => {
localStorage.setItem(`${lsKeyPrefix}[${id}]`, JSON.stringify(true))

Choose a reason for hiding this comment

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

[❗❗ correctness]
Consider handling potential exceptions from localStorage.setItem. If localStorage is full or unavailable, this could throw an error, impacting the application's stability.

icon?: ReactNode;
id: string;
message: string;
type: string;

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider using a union type for notification.type to restrict it to known values like 'banner'. This will improve type safety and prevent errors from unexpected values.

)
}

return <></>

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Returning an empty fragment (<></>) might not be the best approach if the notification type is not 'banner'. Consider handling other types or providing a fallback UI to improve clarity and maintainability.

icon?: ReactNode;
id: string;
message: string;
type: string;

Choose a reason for hiding this comment

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

Consider using a union type for type to restrict it to known values, such as 'banner' | 'alert' | 'info', to improve type safety.

)
}

return <></>

Choose a reason for hiding this comment

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

Returning an empty fragment <> </> might not be the best approach for handling unsupported notification types. Consider logging a warning or handling other types explicitly.

@import '../../../styles/includes';

.wrap {
background: #60267D;

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider using a CSS variable or a SCSS variable for the background color instead of hardcoding #60267D. This improves maintainability by allowing easier updates and consistency across the application.

flex: 0 0;
margin-left: auto;
border-radius: 50%;
border: 2px solid white;

Choose a reason for hiding this comment

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

[⚠️ maintainability]
The border color white is hardcoded. Consider using a SCSS variable for consistency and easier updates.

@import '../../../styles/includes';

.wrap {
background: #60267D;

Choose a reason for hiding this comment

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

Consider using a variable for the background color instead of a hardcoded hex value to maintain consistency and ease of updates across the project.

flex: 0 0;
margin-left: auto;
border-radius: 50%;
border: 2px solid white;

Choose a reason for hiding this comment

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

Consider using a variable for the border color instead of hardcoding 'white'. This will help maintain consistency and make future updates easier.

description: 'Content displayed inside the notification banner',
},
persistent: {
defaultValue: false,

Choose a reason for hiding this comment

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

Consider using control to define the type of control for the persistent prop in argTypes to enhance the Storybook UI experience.


export const Primary: Story = {
args: {
content: 'Help tooltip',

Choose a reason for hiding this comment

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

The content argument is set to a generic string 'Help tooltip'. Consider providing a more descriptive or varied example to better demonstrate the component's capabilities.

description: 'Content displayed inside the notification banner',
},
persistent: {
defaultValue: false,

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider adding a type annotation for defaultValue to ensure type safety and clarity. This can help prevent unintended type-related bugs.

},
},
component: NotificationBanner,
excludeStories: /.*Decorator$/,

Choose a reason for hiding this comment

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

[💡 maintainability]
The regex /.*Decorator$/ used in excludeStories might unintentionally exclude stories that do not follow the intended naming convention. Consider refining the regex to match specific patterns if necessary.


import { InformationCircleIcon } from '@heroicons/react/outline'

import { IconOutline } from '../../svgs'

Choose a reason for hiding this comment

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

The import statement for IconOutline seems unnecessary if only XIcon is used. Consider importing XIcon directly to improve clarity and potentially reduce bundle size.

<div className={styles.inner}>
{props.icon || (
<div className={styles.icon}>
<InformationCircleIcon className='icon-xl' />

Choose a reason for hiding this comment

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

Consider adding aria-hidden="true" to the InformationCircleIcon to improve accessibility, as it appears to be decorative.


{!props.persistent && (
<div className={styles.close} onClick={handleClose}>
<IconOutline.XIcon className='icon-lg' />

Choose a reason for hiding this comment

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

Consider adding aria-label or title to the close button for better accessibility, as screen readers may not convey the purpose of the button without additional context.


const NotificationBanner: FC<NotificationBannerProps> = props => {
const handleClose = useCallback(() => {
props.onClose?.(true)

Choose a reason for hiding this comment

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

[❗❗ correctness]
The handleClose function calls props.onClose?.(true), which assumes that the onClose callback can handle a boolean argument. Ensure that all usages of NotificationBanner pass an onClose function that correctly handles this argument to avoid potential runtime errors.

}, [props.onClose])

return (
<div className={styles.wrap}>

Choose a reason for hiding this comment

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

[⚠️ maintainability]
Consider adding an aria-label or role attribute to the close button for better accessibility. This will help screen readers identify the purpose of the button.

@@ -0,0 +1,2 @@
export * from './banner'
export { default as Notification } from './Notification'

Choose a reason for hiding this comment

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

[❗❗ correctness]
Ensure that the Notification component is properly exported as a default export in the ./Notification module. If it is not, this line will cause an import error.

@vas3a vas3a closed this Oct 16, 2025
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.

2 participants