Conversation
WalkthroughSystem-wide UI styling updates replace specific Tailwind color shades with simplified tokens and theme-driven colors. Multiple badges and icons switch palettes. Minor formatting adds trailing commas in mutation options without behavior changes. Email chart now derives colors via useColors with a helper mapping statuses to theme colors. No public APIs changed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant EmailChart as EmailChart
participant useColors as Theme Colors
participant Item as EmailChartItem
participant Tooltip as Tooltip/UI
EmailChart->>useColors: get currentColors
loop for each metric/status
EmailChart->>Item: render(status, value, currentColors)
Item->>Item: getColorForStatus(status, currentColors)
Item-->>EmailChart: color string
end
EmailChart->>Tooltip: render entries with inline style background using color
Tooltip-->>EmailChart: visible themed legend/dots
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsx (1)
108-108: Typo: border-broder → border-border.The container loses its border because of the misspelling.
Apply this diff:
- <div className="flex flex-col rounded-xl border border-broder shadow"> + <div className="flex flex-col rounded-xl border border-border shadow">apps/web/src/app/(dashboard)/dashboard/email-chart.tsx (1)
291-294: Guard against non-finite percentages to prevent crashes.If total sent is 0 but a numerator > 0, percentage can be Infinity and toFixed will throw. Add a finite check.
Apply this diff:
- {status !== "total" - ? `(${count > 0 ? (percentage * 100).toFixed(0) : 0}%)` - : null} + {status !== "total" + ? `(${ + count > 0 && Number.isFinite(percentage) + ? (percentage * 100).toFixed(0) + : 0 + }%)` + : null}
🧹 Nitpick comments (11)
apps/web/src/components/payments/UpgradeModal.tsx (1)
55-55: Hide decorative check icon from screen readers.The icon is purely presentational next to text; mark it decorative.
Apply:
- <CheckCircle2 className="h-4 w-4 text-green flex-shrink-0 mt-0.5" /> + <CheckCircle2 aria-hidden="true" className="h-4 w-4 text-green flex-shrink-0 mt-0.5" />apps/web/src/components/payments/PlanDetails.tsx (1)
39-39: Hide decorative check icon from screen readers.Improve a11y for the perks list.
Apply:
- <CheckCircle2 className="h-4 w-4 text-green flex-shrink-0" /> + <CheckCircle2 aria-hidden="true" className="h-4 w-4 text-green flex-shrink-0" />apps/web/src/app/(dashboard)/payments/page.tsx (1)
40-40: Hide decorative success icon from screen readers.Mark the success icon decorative; the adjacent text conveys the message.
Apply:
- <CheckCircle2 className="h-4 w-4 text-green flex-shrink-0" /> + <CheckCircle2 aria-hidden="true" className="h-4 w-4 text-green flex-shrink-0" />apps/web/src/app/(dashboard)/templates/duplicate-template.tsx (1)
32-39: Surface errors on duplicate failureConsider adding onError to inform users if duplication fails.
{ onSuccess: () => { utils.template.getTemplates.invalidate(); setOpen(false); toast.success(`Template duplicated`); }, + onError: (e) => { + toast.error(`Template not duplicated: ${e.message ?? "Unknown error"}`); + }, },apps/web/src/app/(dashboard)/domains/status-indicator.tsx (2)
6-23: Simplify color mappingA small map is clearer and type-safe.
- let badgeColor = "bg-gray"; // Default color - switch (status) { - case DomainStatus.NOT_STARTED: - badgeColor = "bg-gray"; - break; - case DomainStatus.SUCCESS: - badgeColor = "bg-green"; - break; - case DomainStatus.FAILED: - badgeColor = "bg-red"; - break; - case DomainStatus.TEMPORARY_FAILURE: - case DomainStatus.PENDING: - badgeColor = "bg-yellow"; - break; - default: - badgeColor = "bg-gray"; - } + const colorByStatus: Record<DomainStatus, string> = { + [DomainStatus.NOT_STARTED]: "bg-gray", + [DomainStatus.SUCCESS]: "bg-green", + [DomainStatus.FAILED]: "bg-red", + [DomainStatus.TEMPORARY_FAILURE]: "bg-yellow", + [DomainStatus.PENDING]: "bg-yellow", + }; + const badgeColor = colorByStatus[status] ?? "bg-gray";
6-23: Decorative-only indicator: mark hidden from a11y treeIf a textual status label is adjacent, hide this purely visual bar from assistive tech.
- return <div className={` w-[2px] ${badgeColor} my-1.5 rounded-full`}></div>; + return ( + <div + role="presentation" + aria-hidden="true" + className={`w-[2px] ${badgeColor} my-1.5 rounded-full`} + /> + );apps/web/src/app/(dashboard)/campaigns/campaign-list.tsx (1)
105-110: Status badge token swap looks good; consider centralizing badge variants.The new bg/text/border tokens align with the PR’s theme direction. Consider extracting a small Badge component or a status→class map to keep variants consistent across screens.
apps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsx (1)
89-101: Minor consistency nit: “All” vs “all”.Other pages (e.g., campaigns list) use "all" (lowercase) in Select values. Aligning here would reduce mental overhead when scanning URL params and handlers.
apps/web/src/app/(dashboard)/dashboard/email-chart.tsx (1)
255-273: Local status→color mapping works; consider deduping.getColorForStatus mirrors logic likely used by EmailStatusIcon. To avoid drift, consider moving this mapping next to useColors() (e.g., export a helper) and reusing it here and in icons.
apps/web/src/app/(dashboard)/settings/team/delete-team-member.tsx (2)
41-41: Trailing comma: fine; tiny polish opportunity in handlersNo behavior change—good for diffs. Minor nit: the onSuccess/onError callbacks are marked async but don’t await anything. Either await the invalidate or drop async to avoid implied floating promises.
Example outside this line range:
onSuccess: async () => { await utils.team.getTeamUsers.invalidate(); setOpen(false); toast.success("Team member removed successfully"); }, onError: (error) => { toast.error(error.message); },
53-53: Prefer semantic tokens for destructive color; add accessible label on icon-only triggerIf your theme exposes a semantic token (e.g., text-destructive), use that over raw red for consistency and theming. Also, this trigger is icon-only—add an accessible name.
Proposed diff within this block:
- <Button variant="ghost" size="sm"> + <Button + variant="ghost" + size="sm" + aria-label={self ? "Leave team" : "Remove team member"} + > - <LogOut className="h-4 w-4 text-red/80" /> + <LogOut className="h-4 w-4 text-destructive/80" /> ... - <Trash2 className="h-4 w-4 text-red/80" /> + <Trash2 className="h-4 w-4 text-destructive/80" />If text-destructive isn’t defined, please confirm that text-red (without shade) is configured with a DEFAULT in your Tailwind theme so text-red/80 compiles as intended.
Also applies to: 55-55
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (24)
apps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsx(1 hunks)apps/web/src/app/(dashboard)/campaigns/campaign-list.tsx(1 hunks)apps/web/src/app/(dashboard)/campaigns/delete-campaign.tsx(2 hunks)apps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsx(2 hunks)apps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsx(1 hunks)apps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsx(2 hunks)apps/web/src/app/(dashboard)/contacts/delete-contact-book.tsx(3 hunks)apps/web/src/app/(dashboard)/dashboard/email-chart.tsx(6 hunks)apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx(2 hunks)apps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsx(2 hunks)apps/web/src/app/(dashboard)/domains/[domainId]/page.tsx(6 hunks)apps/web/src/app/(dashboard)/domains/domain-badge.tsx(1 hunks)apps/web/src/app/(dashboard)/domains/status-indicator.tsx(1 hunks)apps/web/src/app/(dashboard)/emails/cancel-email.tsx(2 hunks)apps/web/src/app/(dashboard)/emails/email-list.tsx(4 hunks)apps/web/src/app/(dashboard)/payments/page.tsx(1 hunks)apps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsx(2 hunks)apps/web/src/app/(dashboard)/settings/team/delete-team-member.tsx(2 hunks)apps/web/src/app/(dashboard)/settings/team/team-members-list.tsx(2 hunks)apps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx(6 hunks)apps/web/src/app/(dashboard)/templates/delete-template.tsx(2 hunks)apps/web/src/app/(dashboard)/templates/duplicate-template.tsx(2 hunks)apps/web/src/components/payments/PlanDetails.tsx(1 hunks)apps/web/src/components/payments/UpgradeModal.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
{apps,packages}/**/*.{js,jsx,ts,tsx,css,scss,md,mdx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Prettier with the Tailwind plugin for code formatting
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
{apps,packages}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{apps,packages}/**/*.{js,jsx,ts,tsx}: Group imports by source (internal/external) and alphabetize them
Use camelCase for variables and functions, PascalCase for components and classes
Use try/catch with specific error types for error handling
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{apps,packages}/**/*.{ts,tsx}: Use strong typing in TypeScript, avoidany, and use Zod for validation
Follow Vercel style guides with strict TypeScript
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
{apps,packages}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{apps,packages}/**/*.{jsx,tsx}: Use functional React components with hooks and group related hooks together
In React components, structure code with props at the top, hooks next, helper functions, then JSX
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use tRPC for internal API endpoints
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Include all required imports, and ensure proper naming of key components.
Files:
apps/web/src/app/(dashboard)/emails/cancel-email.tsxapps/web/src/app/(dashboard)/domains/status-indicator.tsxapps/web/src/components/payments/PlanDetails.tsxapps/web/src/app/(dashboard)/payments/page.tsxapps/web/src/app/(dashboard)/domains/domain-badge.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsxapps/web/src/app/(dashboard)/templates/duplicate-template.tsxapps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsxapps/web/src/components/payments/UpgradeModal.tsxapps/web/src/app/(dashboard)/campaigns/delete-campaign.tsxapps/web/src/app/(dashboard)/settings/team/team-members-list.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-member.tsxapps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsxapps/web/src/app/(dashboard)/campaigns/campaign-list.tsxapps/web/src/app/(dashboard)/dashboard/email-chart.tsxapps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsxapps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsxapps/web/src/app/(dashboard)/contacts/delete-contact-book.tsxapps/web/src/app/(dashboard)/templates/delete-template.tsxapps/web/src/app/(dashboard)/domains/[domainId]/page.tsxapps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsxapps/web/src/app/(dashboard)/emails/email-list.tsxapps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx
🧬 Code graph analysis (1)
apps/web/src/app/(dashboard)/dashboard/email-chart.tsx (1)
apps/web/src/app/(dashboard)/dashboard/hooks/useColors.ts (1)
useColors(3-27)
🔇 Additional comments (38)
apps/web/src/app/(dashboard)/emails/cancel-email.tsx (2)
67-67: Trailing comma formatting: LGTM.Matches Prettier style; no behavioral change.
79-81: Add accessible name to icon-only destructive button and mark icon as decorative- <Button variant="ghost" size="sm"> - <Trash2 className="h-4 w-4 text-red" /> + <Button variant="ghost" size="sm" aria-label="Cancel email"> + <Trash2 aria-hidden="true" className="h-4 w-4 text-red" />Confirm Tailwind theme defines
text-red/text-green(ordestructive/success) tokens and opacity variants like/80.apps/web/src/app/(dashboard)/templates/delete-template.tsx (2)
65-65: Trailing comma formatting: LGTM.Consistent with the rest of the PR.
77-79: I’ve requested the file context to verify prop support and imports.apps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsx (1)
65-66: Trailing comma in mutate options — OKFormatting-only; aligns with Prettier’s trailingComma=all. No runtime impact.
apps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsx (1)
69-71: Trailing comma in mutate options — OKConsistent with repo formatting; no behavior change.
apps/web/src/app/(dashboard)/templates/duplicate-template.tsx (1)
38-39: Trailing comma in mutate options — OKFormatting-only change; consistent across the PR.
apps/web/src/app/(dashboard)/contacts/delete-contact-book.tsx (2)
49-50: Trailing comma in function params — OKPrettier-friendly; reduces future diff churn.
68-69: Trailing comma in mutate options — OKFormatting-only; consistent with the rest of the PR.
apps/web/src/app/(dashboard)/domains/status-indicator.tsx (1)
6-23: No missing DEFAULT color tokens – Verified in packages/tailwind-config/tailwind.config.ts thatgray,green,red, andyelloware each defined under extend.colors with a DEFAULT value (e.g. green: { DEFAULT: "hsl(var(--green))" }), so bg-gray/green/red/yellow will resolve correctly.apps/web/src/app/(dashboard)/contacts/[contactBookId]/contact-list.tsx (2)
155-156: Subscribed badge styles updated correctly.Tokenized bg/text/border classes are consistent with the rest of the PR.
161-163: Unsubscribed badge + trailing comma LGTM.Color tokens and the added trailing comma (prettier-friendly) are good.
Also applies to: 169-170
apps/web/src/app/(dashboard)/dashboard/email-chart.tsx (1)
129-133: Tooltip dots now correctly follow theme colors.Inline styles sourced from useColors() remove hard-coded hexes. Looks solid.
Also applies to: 141-145, 153-158, 167-170, 179-182
apps/web/src/app/(dashboard)/settings/team/team-members-list.tsx (2)
70-72: Active badge token swap LGTM.Consistent with the PR’s palette simplification.
125-127: Pending badge token swap LGTM.Matches the new yellow token usage elsewhere.
apps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx (2)
156-158: Status dot color tokens updated correctly.bg-yellow → saving; bg-green → saved. Looks consistent with the new system.
32-32: Trailing commas: consistency with Prettier.No behavior change; matches formatting guidelines.
Also applies to: 90-90, 146-147, 192-192
apps/web/src/app/(dashboard)/campaigns/[campaignId]/page.tsx (1)
148-187: LGTM! Color token simplification aligns with system-wide theming updates.The update from specific numeric color shades (e.g.,
bg-green-500,bg-red-400) to simplified base tokens (e.g.,bg-green/30,bg-red/30) creates a cleaner, more maintainable color system. The badge logic remains intact with proper status-to-color mapping.apps/web/src/app/(dashboard)/domains/domain-badge.tsx (1)
6-20: LGTM! Consistent color token updates improve theming maintainability.The transition from dark-mode aware color variants to simplified base tokens (e.g.,
bg-green/15 text-greeninstead of complex dark mode variants) creates better consistency across the dashboard while maintaining visual hierarchy through opacity variations.apps/web/src/app/(dashboard)/emails/email-list.tsx (5)
48-50: LGTM! Trailing comma improves formatting consistency.Adding the trailing comma to the options object follows the project's Prettier configuration and improves consistency across the codebase.
53-55: LGTM! Trailing comma improves formatting consistency.Adding the trailing comma maintains consistency with the formatting applied to the other dynamic import above.
233-235: LGTM! Trailing comma maintains formatting consistency.The trailing comma addition follows the established formatting pattern and doesn't affect the date formatting functionality.
249-251: LGTM! Trailing comma maintains formatting consistency.Consistent with the other date formatting change above, this maintains the project's formatting standards.
299-346: LGTM! Color token simplification improves theming consistency.The EmailIcon component's color updates from specific Tailwind shades (e.g.,
text-gray-500,text-emerald-800) to simplified base tokens (e.g.,text-gray,text-green) aligns with the system-wide theming improvements while maintaining the same visual status mapping.apps/web/src/app/(dashboard)/domains/[domainId]/page.tsx (6)
44-46: LGTM! Formatting improvement with trailing comma removal.Removing the trailing comma from the
useQueryoptions object aligns with the project's formatting standards.
56-58: LGTM! Consistent formatting with trailing comma removal.This change maintains consistency with the similar formatting applied to the
useQueryoptions above.
234-236: LGTM! Minor formatting improvement.The formatting change to the initial state assignment doesn't affect functionality and maintains code consistency.
247-249: LGTM! Trailing comma removal for consistency.This formatting change aligns with the similar updates made to other mutation options in the file.
260-262: LGTM! Consistent formatting across mutations.The trailing comma removal maintains consistency with the other mutation option formatting in the file.
305-329: LGTM! Color token updates align with theming improvements.The
DnsVerificationStatuscomponent's color updates match the same simplified token pattern used throughout the dashboard, replacing complex color specifications with cleaner base tokens likebg-green/15 text-greenwhile preserving the status-to-color mapping logic.apps/web/src/app/(dashboard)/dev-settings/api-keys/add-api-key.tsx (2)
65-65: Consistent formatting with mutation options.The trailing comma follows modern JavaScript formatting conventions and maintains consistency across the codebase.
135-135: Theme-consistent color simplification.The change from
text-green-500totext-greenaligns with the project's custom theme configuration that defines simplified base color tokens, contributing to the overall dashboard color consistency improvements.apps/web/src/app/(dashboard)/campaigns/delete-campaign.tsx (2)
65-65: Formatting consistency maintained.The trailing comma in the mutation options object follows modern JavaScript conventions.
78-78: Simplified color token implementation.The change from
text-red-600/80totext-red/80is consistent with the theme-driven color updates across the dashboard, simplifying the color system while maintaining visual consistency.apps/web/src/app/(dashboard)/campaigns/duplicate-campaign.tsx (2)
38-38: Proper mutation options formatting.The trailing comma maintains consistency with modern JavaScript formatting standards.
49-49: Coherent theme color update.The change from
text-blue-600/80totext-blue/80follows the same pattern as other icon color updates throughout the PR, contributing to a unified color system across the dashboard.apps/web/src/app/(dashboard)/settings/team/delete-team-invite.tsx (2)
39-39: Standard formatting convention applied.The trailing comma in the mutation options object follows JavaScript best practices and maintains codebase consistency.
50-50: Unified color token system.The simplification from
text-red-600/80totext-red/80aligns with the systematic color token updates across the dashboard, creating a more maintainable and consistent design system.
| <DialogTrigger asChild> | ||
| <Button variant="ghost" size="sm"> | ||
| <Trash2 className="h-4 w-4 text-red-600/80" /> | ||
| <Trash2 className="h-4 w-4 text-red/80" /> | ||
| </Button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Icon-only trigger: add aria-label and hover color for parity
Match other delete actions’ hover treatment and expose an accessible label.
- <DialogTrigger asChild>
- <Button variant="ghost" size="sm">
- <Trash2 className="h-4 w-4 text-red/80" />
- </Button>
- </DialogTrigger>
+ <DialogTrigger asChild>
+ <Button
+ variant="ghost"
+ size="sm"
+ aria-label={`Delete contact ${contact.email ?? ""}`}
+ title="Delete contact"
+ >
+ <Trash2 className="h-4 w-4 text-red/80 hover:text-red/70" />
+ </Button>
+ </DialogTrigger>📝 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.
| <DialogTrigger asChild> | |
| <Button variant="ghost" size="sm"> | |
| <Trash2 className="h-4 w-4 text-red-600/80" /> | |
| <Trash2 className="h-4 w-4 text-red/80" /> | |
| </Button> | |
| <DialogTrigger asChild> | |
| - <Button variant="ghost" size="sm"> | |
| - <Trash2 className="h-4 w-4 text-red/80" /> | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| aria-label={`Delete contact ${contact.email ?? ""}`} | |
| title="Delete contact" | |
| > | |
| <Trash2 className="h-4 w-4 text-red/80 hover:text-red/70" /> | |
| </Button> | |
| </DialogTrigger> |
🤖 Prompt for AI Agents
In apps/web/src/app/(dashboard)/contacts/[contactBookId]/delete-contact.tsx
around lines 80 to 83, the icon-only DialogTrigger/Button lacks an accessible
label and doesn't match other delete actions' hover color; add an aria-label
(e.g., aria-label="Delete contact") to the trigger/button and update the
button/icon classes to include the same hover color used by other delete buttons
(e.g., hover text-red/100 or hover:text-red/90) so the icon has a visible hover
state and is accessible to screen readers.
| <DialogTrigger asChild> | ||
| <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent "> | ||
| <Trash2 className="h-[18px] w-[18px] text-red-600/80 hover:text-red-600/70" /> | ||
| <Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" /> | ||
| </Button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Tidy className and add accessible label
Remove trailing space in className and add an aria-label for the icon-only trigger.
- <DialogTrigger asChild>
- <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent ">
- <Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" />
- </Button>
- </DialogTrigger>
+ <DialogTrigger asChild>
+ <Button
+ variant="ghost"
+ size="sm"
+ className="p-0 hover:bg-transparent"
+ aria-label={`Delete contact book ${contactBook.name ?? ""}`}
+ title="Delete contact book"
+ >
+ <Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" />
+ </Button>
+ </DialogTrigger>📝 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.
| <DialogTrigger asChild> | |
| <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent "> | |
| <Trash2 className="h-[18px] w-[18px] text-red-600/80 hover:text-red-600/70" /> | |
| <Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" /> | |
| </Button> | |
| <DialogTrigger asChild> | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| className="p-0 hover:bg-transparent" | |
| aria-label={`Delete contact book ${contactBook.name ?? ""}`} | |
| title="Delete contact book" | |
| > | |
| <Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" /> | |
| </Button> | |
| </DialogTrigger> |
🤖 Prompt for AI Agents
In apps/web/src/app/(dashboard)/contacts/delete-contact-book.tsx around lines 79
to 82, remove the trailing space from the Button's className value and add an
accessible label to the icon-only trigger by providing an aria-label (e.g.,
aria-label="Delete contact") on the Button element so screen readers can
describe the action.
| <DialogTrigger asChild> | ||
| <Button variant="ghost" size="sm"> | ||
| <Trash2 className="h-4 w-4 text-red-600/80" /> | ||
| <Trash2 className="h-4 w-4 text-red/80" /> | ||
| </Button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Icon-only trigger: add accessible label and consistent hover color
Add an aria-label for screen readers and align hover color with other delete triggers in this PR.
Apply:
- <DialogTrigger asChild>
- <Button variant="ghost" size="sm">
- <Trash2 className="h-4 w-4 text-red/80" />
- </Button>
- </DialogTrigger>
+ <DialogTrigger asChild>
+ <Button
+ variant="ghost"
+ size="sm"
+ aria-label={`Delete API key ${apiKey.name ?? ""}`}
+ title="Delete API key"
+ >
+ <Trash2 className="h-4 w-4 text-red/80 hover:text-red/70" />
+ </Button>
+ </DialogTrigger>📝 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.
| <DialogTrigger asChild> | |
| <Button variant="ghost" size="sm"> | |
| <Trash2 className="h-4 w-4 text-red-600/80" /> | |
| <Trash2 className="h-4 w-4 text-red/80" /> | |
| </Button> | |
| <DialogTrigger asChild> | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| aria-label={`Delete API key ${apiKey.name ?? ""}`} | |
| title="Delete API key" | |
| > | |
| <Trash2 className="h-4 w-4 text-red/80 hover:text-red/70" /> | |
| </Button> | |
| </DialogTrigger> |
🤖 Prompt for AI Agents
In apps/web/src/app/(dashboard)/dev-settings/api-keys/delete-api-key.tsx around
lines 76-79, the icon-only DialogTrigger/Button lacks an accessible label and
its hover color doesn't match other delete triggers; add an aria-label (e.g.,
aria-label="Delete API key") to the Button so screen readers announce its
purpose, and update the button/icon hover color class to match the other delete
controls in this PR (use the same hover text color utility used elsewhere for
delete actions).
| template.content ? JSON.parse(template.content) : undefined, | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Harden JSON parse + avoid any.
Bad template.content would throw at render. Also, prefer avoiding any per guidelines.
Apply this diff:
- const [json, setJson] = useState<Record<string, any> | undefined>(
- template.content ? JSON.parse(template.content) : undefined,
- );
+ const [json, setJson] = useState<Record<string, unknown> | undefined>(() => {
+ try {
+ return template.content ? JSON.parse(template.content) : undefined;
+ } catch {
+ return undefined;
+ }
+ });📝 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.
| template.content ? JSON.parse(template.content) : undefined, | |
| ); | |
| const [json, setJson] = useState<Record<string, unknown> | undefined>(() => { | |
| try { | |
| return template.content ? JSON.parse(template.content) : undefined; | |
| } catch { | |
| return undefined; | |
| } | |
| }); |
🤖 Prompt for AI Agents
In apps/web/src/app/(dashboard)/templates/[templateId]/edit/page.tsx around
lines 66-67, JSON.parse(template.content) can throw on bad input and the result
is currently typed as any; wrap the parse in a safe parse (try/catch) that
returns undefined on error (or uses a small helper like safeJsonParse) and
replace any with a concrete type (e.g., TemplateContent | undefined) or unknown
narrowed to the expected shape; ensure you handle the undefined fallback in the
component so render won’t crash if content is invalid.
| <DialogTrigger asChild> | ||
| <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent"> | ||
| <Copy className="h-[18px] w-[18px] text-blue-600/80" /> | ||
| <Copy className="h-[18px] w-[18px] text-blue/80" /> | ||
| </Button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Icon-only trigger: add aria-label and hover color
Improve a11y and keep visual behavior consistent with delete buttons.
- <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent">
- <Copy className="h-[18px] w-[18px] text-blue/80" />
+ <Button
+ variant="ghost"
+ size="sm"
+ className="p-0 hover:bg-transparent"
+ aria-label={`Duplicate ${template.name ?? "template"}`}
+ title="Duplicate template"
+ >
+ <Copy className="h-[18px] w-[18px] text-blue/80 hover:text-blue/70" />
</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.
| <DialogTrigger asChild> | |
| <Button variant="ghost" size="sm" className="p-0 hover:bg-transparent"> | |
| <Copy className="h-[18px] w-[18px] text-blue-600/80" /> | |
| <Copy className="h-[18px] w-[18px] text-blue/80" /> | |
| </Button> | |
| <DialogTrigger asChild> | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| className="p-0 hover:bg-transparent" | |
| aria-label={`Duplicate ${template.name ?? "template"}`} | |
| title="Duplicate template" | |
| > | |
| <Copy className="h-[18px] w-[18px] text-blue/80 hover:text-blue/70" /> | |
| </Button> |
🤖 Prompt for AI Agents
In apps/web/src/app/(dashboard)/templates/duplicate-template.tsx around lines 47
to 50, the icon-only DialogTrigger/Button lacks an accessible label and its
hover behavior differs from delete buttons; add an aria-label (e.g.,
aria-label="Duplicate template") to the Button so screen readers can describe
the action, and change the hover class to match the delete button hover style
used elsewhere in the codebase (copy the same hover:bg-... class from the delete
button) so visual behavior is consistent.
Summary by CodeRabbit