feat(custom): implement SubscriptionTable scaffolding and register global module exports - #1660
Conversation
…ule exports Signed-off-by: Abhinav Deval <abhinavkdeval08@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a new SubscriptionTable component to compare free, team, and enterprise subscription plans, along with its custom styled components. The feedback suggests integrating the newly defined custom styled components from style.tsx into the main table component to clean up unused Material-UI imports, and exposing hardcoded UI strings as configurable props to support internationalization (i18n).
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| import CheckIcon from '@mui/icons-material/Check'; | ||
| import CloseIcon from '@mui/icons-material/Close'; | ||
| import { | ||
| Box, | ||
| Button, | ||
| Paper, | ||
| Table, | ||
| TableBody, | ||
| TableCell, | ||
| TableContainer, | ||
| TableHead, | ||
| TableRow, | ||
| Typography | ||
| } from '@mui/material'; | ||
| import React from 'react'; |
There was a problem hiding this comment.
Import the custom styled components from ./style and clean up the unused MUI imports (Paper, TableCell, TableContainer, TableRow) to keep the code clean and leverage the custom styling defined for this component.
| import CheckIcon from '@mui/icons-material/Check'; | |
| import CloseIcon from '@mui/icons-material/Close'; | |
| import { | |
| Box, | |
| Button, | |
| Paper, | |
| Table, | |
| TableBody, | |
| TableCell, | |
| TableContainer, | |
| TableHead, | |
| TableRow, | |
| Typography | |
| } from '@mui/material'; | |
| import React from 'react'; | |
| import CheckIcon from '@mui/icons-material/Check'; | |
| import CloseIcon from '@mui/icons-material/Close'; | |
| import { | |
| Box, | |
| Button, | |
| Table, | |
| TableBody, | |
| TableHead, | |
| Typography | |
| } from '@mui/material'; | |
| import React from 'react'; | |
| import { | |
| StyledTableContainer, | |
| StyledHeaderRow, | |
| StyledTableCell, | |
| FeatureHeaderCell | |
| } from './style'; |
| export interface SubscriptionTableProps { | ||
| title?: string; | ||
| features: PlanFeature[]; | ||
| onPlanSelect?: (planType: 'free' | 'team' | 'enterprise') => void; | ||
| } | ||
|
|
||
| export const SubscriptionTable: React.FC<SubscriptionTableProps> = ({ | ||
| title = 'Subscription Plans Comparison', | ||
| features, | ||
| onPlanSelect | ||
| }) => { |
There was a problem hiding this comment.
To support internationalization (i18n) and localization, avoid hardcoding UI strings (such as table headers and button labels) in shared components. Expose these strings as configurable props with default values to maintain backward compatibility. Additionally, default the features prop to an empty array [] to prevent runtime errors if it is not provided.
export interface SubscriptionTableProps {
title?: string;
features?: PlanFeature[];
onPlanSelect?: (planType: 'free' | 'team' | 'enterprise') => void;
featuresLabel?: string;
freePlanLabel?: string;
freePlanButtonLabel?: string;
teamPlanLabel?: string;
teamPlanButtonLabel?: string;
enterprisePlanLabel?: string;
enterprisePlanButtonLabel?: string;
}
export const SubscriptionTable: React.FC<SubscriptionTableProps> = ({
title = 'Subscription Plans Comparison',
features = [],
onPlanSelect,
featuresLabel = 'Features',
freePlanLabel = 'Free Plan',
freePlanButtonLabel = 'Get Started',
teamPlanLabel = 'Team Plan',
teamPlanButtonLabel = 'Upgrade',
enterprisePlanLabel = 'Enterprise Plan',
enterprisePlanButtonLabel = 'Contact Us'
}) => {
References
- Avoid hardcoding UI strings (such as button labels) in shared components. Expose these strings as configurable props to support internationalization (i18n) and localization.
- When exposing UI strings as configurable props in shared components to support localization, provide a default value to maintain backward compatibility.
| <TableContainer component={Paper} elevation={2} sx={{ borderRadius: 2, overflow: 'hidden' }}> | ||
| <Table sx={{ minWidth: 650 }} aria-label="subscription comparison table"> | ||
| <TableHead sx={{ backgroundColor: 'action.hover' }}> | ||
| <TableRow> | ||
| <TableCell sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}>Features</TableCell> | ||
| <TableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}> | ||
| Free Plan | ||
| <Box sx={{ mt: 1 }}> | ||
| <Button size="small" variant="outlined" onClick={() => onPlanSelect?.('free')}> | ||
| Get Started | ||
| </Button> | ||
| </Box> | ||
| </TableCell> | ||
| <TableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}> | ||
| Team Plan | ||
| <Box sx={{ mt: 1 }}> | ||
| <Button | ||
| size="small" | ||
| variant="contained" | ||
| color="primary" | ||
| onClick={() => onPlanSelect?.('team')} | ||
| > | ||
| Upgrade | ||
| </Button> | ||
| </Box> | ||
| </TableCell> | ||
| <TableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}> | ||
| Enterprise Plan | ||
| <Box sx={{ mt: 1 }}> | ||
| <Button | ||
| size="small" | ||
| variant="contained" | ||
| color="secondary" | ||
| onClick={() => onPlanSelect?.('enterprise')} | ||
| > | ||
| Contact Us | ||
| </Button> | ||
| </Box> | ||
| </TableCell> | ||
| </TableRow> | ||
| </TableHead> | ||
|
|
||
| <TableBody> | ||
| {features.map((row, index) => ( | ||
| <TableRow | ||
| key={index} | ||
| sx={{ | ||
| '&:last-child td, &:last-child th': { border: 0 }, | ||
| '&:hover': { backgroundColor: 'action.hover' } | ||
| }} | ||
| > | ||
| <TableCell | ||
| component="th" | ||
| scope="row" | ||
| sx={{ fontWeight: 600, color: 'text.primary' }} | ||
| > | ||
| {row.featureName} | ||
| </TableCell> | ||
| <TableCell align="center">{renderValue(row.freePlan)}</TableCell> | ||
| <TableCell align="center">{renderValue(row.teamPlan)}</TableCell> | ||
| <TableCell align="center">{renderValue(row.enterprisePlan)}</TableCell> | ||
| </TableRow> | ||
| ))} | ||
| </TableBody> | ||
| </Table> | ||
| </TableContainer> |
There was a problem hiding this comment.
Update the table rendering to use the imported custom styled components (StyledTableContainer, StyledHeaderRow, StyledTableCell, FeatureHeaderCell) and the configurable localization props instead of hardcoded strings and standard MUI components with inline styles.
<StyledTableContainer>
<Table sx={{ minWidth: 650 }} aria-label="subscription comparison table">
<TableHead>
<StyledHeaderRow>
<StyledTableCell sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}>{featuresLabel}</StyledTableCell>
<StyledTableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}>
{freePlanLabel}
<Box sx={{ mt: 1 }}>
<Button size="small" variant="outlined" onClick={() => onPlanSelect?.('free')}>
{freePlanButtonLabel}
</Button>
</Box>
</StyledTableCell>
<StyledTableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}>
{teamPlanLabel}
<Box sx={{ mt: 1 }}>
<Button
size="small"
variant="contained"
color="primary"
onClick={() => onPlanSelect?.('team')}
>
{teamPlanButtonLabel}
</Button>
</Box>
</StyledTableCell>
<StyledTableCell align="center" sx={{ fontWeight: 'bold', fontSize: '1.1rem' }}>
{enterprisePlanLabel}
<Box sx={{ mt: 1 }}>
<Button
size="small"
variant="contained"
color="secondary"
onClick={() => onPlanSelect?.('enterprise')}
>
{enterprisePlanButtonLabel}
</Button>
</Box>
</StyledTableCell>
</StyledHeaderRow>
</TableHead>
<TableBody>
{features.map((row, index) => (
<TableRow
key={index}
sx={{
'&:last-child td, &:last-child th': { border: 0 },
'&:hover': { backgroundColor: 'action.hover' }
}}
>
<FeatureHeaderCell component="th" scope="row">
{row.featureName}
</FeatureHeaderCell>
<StyledTableCell align="center">{renderValue(row.freePlan)}</StyledTableCell>
<StyledTableCell align="center">{renderValue(row.teamPlan)}</StyledTableCell>
<StyledTableCell align="center">{renderValue(row.enterprisePlan)}</StyledTableCell>
</TableRow>
))}
</TableBody>
</Table>
</StyledTableContainer>
434a2c2 to
b7298c4
Compare
…ule exports Signed-off-by: Abhinav Deval <abhinavkdeval08@gmail.com>
56442e9 to
812e1ac
Compare
|
@KhushamBansal @leecalcote |
|
@leecalcote @KhushamBansal @rishiraj38 @Bhumikagarggg |
Bhumikagarggg
left a comment
There was a problem hiding this comment.
@abhinavkdeval08-design Please review all the suggestions raised by Copilot. If a suggestion is valid, please address it. If not, please reply to the comment explaining why no change is needed so that all comments are resolved.
Signed-off-by: Abhinav Deval <abhinavkdeval08@gmail.com>
b1b798c to
43af05b
Compare
|
@Bhumikagarggg @leecalcote @KhushamBansal |
|
@leecalcote @KhushamBansal @Bhumikagarggg kindly review the PR |
@abhinavkdeval08-design consider and reply to all feedback offered. |
|
@hortison Bro I've already made all the changes you can see and it's ready to review and if this is correct then kindly merge. |
📝 WalkthroughWalkthroughAdds a themed ChangesSubscription table
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/custom/SubscriptionTable/style.tsx`:
- Around line 13-29: Replace raw colors and font-family/weight overrides with
Sistent theme palette and typography tokens across all affected sites: in
src/custom/SubscriptionTable/style.tsx lines 13-29, update StyledHeaderRow,
StyledTableCell, and FeatureHeaderCell to derive colors and typography from the
theme, including theme.palette.text.primary or its Sistent equivalent; in
src/custom/SubscriptionTable/SubscriptionTable.tsx lines 49-65 and 74-104, apply
the appropriate Sistent typography token to the feature and plan header cells
instead of literal family and weight values.
- Around line 5-10: Update the StyledTableContainer styles to allow horizontal
scrolling on narrow viewports instead of clipping the table with overflow
hidden. Preserve the existing visual styles and ensure the 650px-minimum-width
table remains accessible, including later plan columns.
In `@src/custom/SubscriptionTable/SubscriptionTable.tsx`:
- Around line 40-52: Add an accessible text alternative to both boolean branches
in renderValue: label the CheckIcon for the included state and the CloseIcon for
the excluded state using titleAccess, aria-label, or visually hidden text, while
preserving their existing visual styling and test IDs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a195d272-9565-414b-9f9a-519c7ff87d0c
📒 Files selected for processing (5)
src/custom/SubscriptionTable/SubscriptionTable.tsxsrc/custom/SubscriptionTable/index.tssrc/custom/SubscriptionTable/style.tsxsrc/custom/index.tssrc/custom/index.tsx
| export const StyledTableContainer = styled(Paper)(({ theme }) => ({ | ||
| borderRadius: theme.shape.borderRadius * 2, | ||
| overflow: 'hidden', | ||
| boxShadow: theme.shadows[2], | ||
| border: `1px solid ${theme.palette.divider}` | ||
| })); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Allow narrow viewports to scroll the table horizontally.
overflow: 'hidden' clips the 650px-minimum-width table on small screens, preventing access to later plan columns.
Proposed fix
- overflow: 'hidden',
+ overflowX: 'auto',
+ overflowY: 'hidden',📝 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.
| export const StyledTableContainer = styled(Paper)(({ theme }) => ({ | |
| borderRadius: theme.shape.borderRadius * 2, | |
| overflow: 'hidden', | |
| boxShadow: theme.shadows[2], | |
| border: `1px solid ${theme.palette.divider}` | |
| })); | |
| export const StyledTableContainer = styled(Paper)(({ theme }) => ({ | |
| borderRadius: theme.shape.borderRadius * 2, | |
| overflowX: 'auto', | |
| overflowY: 'hidden', | |
| boxShadow: theme.shadows[2], | |
| border: `1px solid ${theme.palette.divider}` | |
| })); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/custom/SubscriptionTable/style.tsx` around lines 5 - 10, Update the
StyledTableContainer styles to allow horizontal scrolling on narrow viewports
instead of clipping the table with overflow hidden. Preserve the existing visual
styles and ensure the 650px-minimum-width table remains accessible, including
later plan columns.
| export const StyledHeaderRow = styled(TableRow)(({ theme }) => ({ | ||
| backgroundColor: theme.palette.mode === 'light' ? '#f9fafb' : '#1e1e1e' | ||
| })); | ||
|
|
||
| // Custom Styled Table Cell for Typography token enforcement | ||
| export const StyledTableCell = styled(TableCell)(({ theme }) => ({ | ||
| fontFamily: 'Open Sans, sans-serif', | ||
| borderColor: theme.palette.divider, | ||
| fontWeight: 500 | ||
| })); | ||
|
|
||
| // Feature Name Column styling (High Emphasis) | ||
| export const FeatureHeaderCell = styled(StyledTableCell)(() => ({ | ||
| fontFamily: 'Qanelas Soft, sans-serif', | ||
| fontWeight: 700, | ||
| color: 'text.primary' | ||
| })); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use Sistent semantic palette and typography tokens throughout this component. color: 'text.primary' in styled() is emitted as a literal CSS value and is not resolved through MUI’s sx token parser, while the raw hex colors and font-family overrides bypass theme configuration.
src/custom/SubscriptionTable/style.tsx#L13-L29: derive header colors, feature-cell color, and typography from Sistent theme exports; usetheme.palette.text.primary(or the Sistent equivalent) rather than the literaltext.primary.src/custom/SubscriptionTable/SubscriptionTable.tsx#L49-L65: replace literal typography weight/family styling with the appropriate Sistent typography token.src/custom/SubscriptionTable/SubscriptionTable.tsx#L74-L104: apply the same tokenized typography to plan header cells.
As per coding guidelines, “Theme-aware UI must use Sistent theme exports and semantic palette tokens rather than raw MUI defaults.”
📍 Affects 2 files
src/custom/SubscriptionTable/style.tsx#L13-L29(this comment)src/custom/SubscriptionTable/SubscriptionTable.tsx#L49-L65src/custom/SubscriptionTable/SubscriptionTable.tsx#L74-L104
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/custom/SubscriptionTable/style.tsx` around lines 13 - 29, Replace raw
colors and font-family/weight overrides with Sistent theme palette and
typography tokens across all affected sites: in
src/custom/SubscriptionTable/style.tsx lines 13-29, update StyledHeaderRow,
StyledTableCell, and FeatureHeaderCell to derive colors and typography from the
theme, including theme.palette.text.primary or its Sistent equivalent; in
src/custom/SubscriptionTable/SubscriptionTable.tsx lines 49-65 and 74-104, apply
the appropriate Sistent typography token to the feature and plan header cells
instead of literal family and weight values.
Source: Coding guidelines
| const renderValue = (value: boolean | string) => { | ||
| if (typeof value === 'boolean') { | ||
| return value ? ( | ||
| <CheckIcon color="success" data-testid="check-icon" /> | ||
| ) : ( | ||
| <CloseIcon color="error" data-testid="close-icon" /> | ||
| ); | ||
| } | ||
| return ( | ||
| <Typography variant="body2" sx={{ fontWeight: 500 }}> | ||
| {value} | ||
| </Typography> | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '1,220p' src/custom/SubscriptionTable/SubscriptionTable.tsxRepository: layer5io/sistent
Length of output: 4928
🏁 Script executed:
cat -n src/custom/SubscriptionTable/SubscriptionTable.tsx | sed -n '1,220p'Repository: layer5io/sistent
Length of output: 5887
Expose a text alternative for the boolean icons in src/custom/SubscriptionTable/SubscriptionTable.tsx:40-46. The check/close icons need an accessible name so screen readers can tell whether a feature is included; add titleAccess, aria-label, or hidden text for both states.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/custom/SubscriptionTable/SubscriptionTable.tsx` around lines 40 - 52, Add
an accessible text alternative to both boolean branches in renderValue: label
the CheckIcon for the included state and the CloseIcon for the excluded state
using titleAccess, aria-label, or visually hidden text, while preserving their
existing visual styling and test IDs.
Description
This PR addresses issue #606 by implementing the missing structural baseline scaffolding for the new
SubscriptionTablecomponent pattern wrapper matrix within the Sistent design system (src/custom).Changes Proposed
src/custom/SubscriptionTable/directory module.SubscriptionTable.tsxutilizing strict type definitions (PlanFeatureprops) to dynamically map features.style.tsxutilizing specialized MUI styled engines and Figma typography token overrides (Qanelas SoftandOpen Sans).src/custom/index.tsandsrc/custom/index.tsx) to expose the API interface.Notes for Reviewers
Signed commits
cc @KhushamBansal @leecalcote @Bhumikagarggg
Summary by CodeRabbit