-
-
Notifications
You must be signed in to change notification settings - Fork 9
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: add reset and retry buttons to episode cards #176
base: main
Are you sure you want to change the base?
Conversation
📝 Walkthrough📝 WalkthroughWalkthroughThe changes in this pull request focus on enhancing the functionality of the Changes
Possibly related PRs
Warning Rate limit exceeded@machetie has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 21 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
📒 Files selected for processing (1)
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
(3 hunks)
🧰 Additional context used
🪛 eslint
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
[error] 24-24: 'invalidateAll' is not defined.
(no-undef)
[error] 40-40: 'invalidateAll' is not defined.
(no-undef)
[error] 122-188: A11y: visible, non-interactive elements with an on:click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as or might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.(a11y-click-events-have-key-events)
(svelte/valid-compile)
[error] 122-188: A11y:
(svelte/valid-compile)
- Add loading states to reset/retry buttons - Add keyboard navigation to episode cards - Improve error handling in media actions - Add ARIA attributes for better accessibility
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: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
📒 Files selected for processing (1)
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
(3 hunks)
🧰 Additional context used
🪛 eslint
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
[error] 18-18: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
[error] 190-190: Classes can only be applied to DOM elements, not components(invalid-class)
(svelte/valid-compile)
let isRetrying = false; | ||
|
||
async function handleMediaAction( | ||
action: (id: string) => Promise<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.
🛠️ Refactor suggestion
Specify a more precise return type instead of any
.
Using any
in TypeScript defeats the purpose of type checking and can lead to runtime errors. Define a specific interface or type for the expected response to enhance type safety and code reliability.
Apply this diff to specify a proper return type:
- action: (id: string) => Promise<any>,
+ action: (id: string) => Promise<{ error?: boolean; [key: string]: any }>,
Alternatively, define a custom interface for the response:
interface ActionResponse {
error?: boolean;
// other relevant properties
}
And update the function signature:
- action: (id: string) => Promise<any>,
+ action: (id: string) => Promise<ActionResponse>,
🧰 Tools
🪛 eslint
[error] 18-18: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
if (selectedEpisodeNumber === episodeNumber) { | ||
selectedEpisodeNumber = null; | ||
} else { | ||
selectedEpisodeNumber = episodeNumber; | ||
} |
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.
🧹 Nitpick (assertive)
Simplify the toggle logic in handleEpisodeClick
.
You can streamline the logic by setting selectedEpisodeNumber
to null
if it's already selected, or to the new episodeNumber
otherwise.
Apply this diff for a cleaner implementation:
function handleEpisodeClick(episodeNumber: number) {
- if (selectedEpisodeNumber === episodeNumber) {
- selectedEpisodeNumber = null;
- } else {
- selectedEpisodeNumber = episodeNumber;
- }
+ selectedEpisodeNumber = selectedEpisodeNumber === episodeNumber ? null : episodeNumber;
}
📝 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.
if (selectedEpisodeNumber === episodeNumber) { | |
selectedEpisodeNumber = null; | |
} else { | |
selectedEpisodeNumber = episodeNumber; | |
} | |
selectedEpisodeNumber = selectedEpisodeNumber === episodeNumber ? null : episodeNumber; |
console.error('Network or unexpected error:', error); | ||
toast.error('Network error occurred. Please check your connection and try again.'); | ||
throw error; |
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.
🧹 Nitpick (assertive)
Avoid re-throwing caught errors after handling.
Since you're already displaying a toast notification and logging the error, re-throwing it might not be necessary and could interrupt the flow.
Apply this diff to prevent re-throwing the error:
} catch (error) {
console.error('Network or unexpected error:', error);
toast.error('Network error occurred. Please check your connection and try again.');
- throw error;
} finally {
📝 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.
console.error('Network or unexpected error:', error); | |
toast.error('Network error occurred. Please check your connection and try again.'); | |
throw error; | |
console.error('Network or unexpected error:', error); | |
toast.error('Network error occurred. Please check your connection and try again.'); |
on:click|stopPropagation={() => resetItem(data.mediaID)} | ||
disabled={isResetting || isRetrying} | ||
> | ||
<CirclePower class="size-4" class:animate-spin={isResetting} /> |
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.
Fix invalid use of class
directive on components.
The class
and class:
directives cannot be applied directly to Svelte components like <CirclePower />
. To apply classes or directives, wrap the component in a DOM element or use a spread attribute if the component supports it.
Apply this diff to fix the issue:
- <CirclePower class="size-4" class:animate-spin={isResetting} />
+ <span class="size-4" class:animate-spin={isResetting}>
+ <CirclePower />
+ </span>
Repeat the same adjustment for the <RotateCcw />
component in the retry button.
📝 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.
<CirclePower class="size-4" class:animate-spin={isResetting} /> | |
<span class="size-4" class:animate-spin={isResetting}> | |
<CirclePower /> | |
</span> |
🧰 Tools
🪛 eslint
[error] 190-190: Classes can only be applied to DOM elements, not components(invalid-class)
(svelte/valid-compile)
on:click|stopPropagation={() => resetItem(data.mediaID)} | ||
disabled={isResetting || isRetrying} | ||
> | ||
<CirclePower class="size-4" class:animate-spin={isResetting} /> | ||
{isResetting ? 'Resetting...' : 'Reset'} | ||
</button> | ||
<button | ||
class="flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed" | ||
on:click|stopPropagation={() => retryItem(data.mediaID)} | ||
disabled={isResetting || isRetrying} | ||
> | ||
<RotateCcw class="size-4" class:animate-spin={isRetrying} /> |
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.
Pass the correct episode ID to resetItem
and retryItem
functions.
Currently, the functions are called with data.mediaID
, which refers to the entire media item. To target the specific episode, pass episode.id
instead.
Apply this diff to fix the IDs being passed:
on:click|stopPropagation={() => resetItem(
- data.mediaID
+ episode.id
)}
on:click|stopPropagation={() => retryItem(
- data.mediaID
+ episode.id
)}
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 eslint
[error] 190-190: Classes can only be applied to DOM elements, not components(invalid-class)
(svelte/valid-compile)
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: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
📒 Files selected for processing (1)
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
(3 hunks)
🧰 Additional context used
🪛 eslint
src/routes/[type=mediaType]/[id]/[season]/+page.svelte
[error] 18-18: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
🔇 Additional comments (1)
src/routes/[type=mediaType]/[id]/[season]/+page.svelte (1)
4-9
: Imports are correctly updated
The necessary modules and components are imported appropriately, ensuring all required functionalities are available.
{#if selectedEpisodeNumber === episode.episode_number && data.mediaItemDetails.find((x) => x.number == episode.episode_number)} | ||
<div | ||
class="absolute inset-0 flex items-center justify-center gap-4 bg-black/40" | ||
> | ||
<button | ||
class="flex items-center gap-2 rounded-md bg-destructive px-4 py-2 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50 disabled:cursor-not-allowed" | ||
on:click|stopPropagation={() => resetItem(episode.id)} | ||
disabled={isResetting || isRetrying} | ||
> | ||
<CirclePower class={`size-4 ${isResetting ? 'animate-spin' : ''}`} /> | ||
{isResetting ? 'Resetting...' : 'Reset'} | ||
</button> | ||
<button | ||
class="flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed" | ||
on:click|stopPropagation={() => retryItem(episode.id)} | ||
disabled={isResetting || isRetrying} | ||
> | ||
<RotateCcw class={`size-4 ${isRetrying ? 'animate-spin' : ''}`} /> | ||
{isRetrying ? 'Retrying...' : 'Retry'} | ||
</button> | ||
</div> | ||
{/if} | ||
|
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.
🧹 Nitpick (assertive)
Optimize repeated lookups by caching media item details
The expression data.mediaItemDetails.find((x) => x.number == episode.episode_number)
is used multiple times within the loop. Consider caching these lookups to improve performance and readability.
You can create a map of mediaItemDetails
before the loop:
<script lang="ts">
// ... existing code
const mediaItemDetailsMap = new Map<number, typeof data.mediaItemDetails[0]>(
data.mediaItemDetails.map((item) => [item.number, item])
);
</script>
Then, within the {#each}
loop, retrieve the item efficiently:
{#each data.details.episodes as episode}
{#if selectedEpisodeNumber === episode.episode_number && mediaItemDetailsMap.has(episode.episode_number)}
<!-- Action buttons -->
{/if}
<!-- Use the cached item elsewhere -->
{#if mediaItemDetailsMap.has(episode.episode_number)}
<div class="mt-1 line-clamp-1 rounded-md bg-zinc-900/60 px-2 text-xs text-white sm:text-sm">
{statesName[mediaItemDetailsMap.get(episode.episode_number)?.state ?? 'Unknown']}
</div>
{/if}
{/each}
This approach avoids repeated find
operations, enhancing performance, especially with larger datasets.
loadingState: { set: (value: boolean) => void } | ||
) { | ||
loadingState.set(true); |
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.
🧹 Nitpick (assertive)
Simplify the loadingState
parameter for clarity
Consider simplifying the loadingState
parameter in handleMediaAction
by passing the setter function directly instead of an object with a set
method. This enhances readability and reduces unnecessary complexity.
Apply this diff to update the function signature and usage:
- loadingState: { set: (value: boolean) => void }
+ loadingState: (value: boolean) => void
Update the function body accordingly:
- loadingState.set(true);
+ loadingState(true);
And similarly for setting it back to false
:
- loadingState.set(false);
+ loadingState(false);
Update the calls to handleMediaAction
in resetItem
:
return await handleMediaAction(
(id) => ItemsService.resetItems({ query: { ids: id.toString() } }),
'Media reset successfully',
'An error occurred while resetting the media',
id,
- { set: (value) => (isResetting = value) }
+ (value) => { isResetting = value }
);
And in retryItem
:
return await handleMediaAction(
(id) => ItemsService.retryItems({ query: { ids: id.toString() } }),
'Media retried successfully',
'An error occurred while retrying the media',
id,
- { set: (value) => (isRetrying = value) }
+ (value) => { isRetrying = value }
);
Committable suggestion skipped: line range outside the PR's diff.
Add reset and retry functionality to episode cards:
Summary by CodeRabbit
New Features
Bug Fixes