-
Notifications
You must be signed in to change notification settings - Fork 3
feat: requests page #12
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
Conversation
|
Warning Rate limit exceeded@rodrigopavezi has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 45 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. WalkthroughThe changes involve the introduction of various configuration files and a structured UI component library for a Next.js application. New React components are created for layout, navigation, and data display, alongside custom hooks for managing payment and request data. Additionally, a GraphQL client is established for data fetching, enhancing the application's organization and functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant GraphQLClient
participant PaymentService
User->>App: Requests latest payments
App->>GraphQLClient: Fetch latest payments
GraphQLClient->>PaymentService: Query payment data
PaymentService-->>GraphQLClient: Return payment data
GraphQLClient-->>App: Send payment data
App-->>User: Display latest payments
sequenceDiagram
participant User
participant App
participant GraphQLClient
participant RequestService
User->>App: Requests latest requests
App->>GraphQLClient: Fetch latest requests
GraphQLClient->>RequestService: Query request data
RequestService-->>GraphQLClient: Return request data
GraphQLClient-->>App: Send request data
App-->>User: Display latest requests
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: 17
Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Files ignored due to path filters (6)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/data.svgis excluded by!**/*.svgpublic/logo-1.svgis excluded by!**/*.svgpublic/logo-2.svgis excluded by!**/*.svgpublic/logo-3.svgis excluded by!**/*.svgsrc/app/icon.icois excluded by!**/*.ico
Files selected for processing (45)
- .eslintrc.json (1 hunks)
- .gitignore (1 hunks)
- README.md (1 hunks)
- components.json (1 hunks)
- next.config.mjs (1 hunks)
- package.json (1 hunks)
- postcss.config.mjs (1 hunks)
- src/app/globals.css (1 hunks)
- src/app/layout.tsx (1 hunks)
- src/app/page.tsx (1 hunks)
- src/app/providers.tsx (1 hunks)
- src/app/requests/page.tsx (1 hunks)
- src/components/footer.tsx (1 hunks)
- src/components/header.tsx (1 hunks)
- src/components/logo.tsx (1 hunks)
- src/components/main-nav.tsx (1 hunks)
- src/components/recent-area.tsx (1 hunks)
- src/components/recent-payment-table.tsx (1 hunks)
- src/components/recent-request-table.tsx (1 hunks)
- src/components/request-table.tsx (1 hunks)
- src/components/search-area.tsx (1 hunks)
- src/components/search.tsx (1 hunks)
- src/components/socials.tsx (1 hunks)
- src/components/stats-area.tsx (1 hunks)
- src/components/ui/avatar.tsx (1 hunks)
- src/components/ui/badge.tsx (1 hunks)
- src/components/ui/button.tsx (1 hunks)
- src/components/ui/card.tsx (1 hunks)
- src/components/ui/dropdown-menu.tsx (1 hunks)
- src/components/ui/input.tsx (1 hunks)
- src/components/ui/sheet.tsx (1 hunks)
- src/components/ui/skeleton.tsx (1 hunks)
- src/components/ui/table.tsx (1 hunks)
- src/lib/apollo-wrapper.tsx (1 hunks)
- src/lib/consts.ts (1 hunks)
- src/lib/currency-manager.ts (1 hunks)
- src/lib/graphQlClient.ts (1 hunks)
- src/lib/hooks/use-latest-payments.tsx (1 hunks)
- src/lib/hooks/use-latest-requests.tsx (1 hunks)
- src/lib/queries/payments.ts (1 hunks)
- src/lib/queries/transactions.ts (1 hunks)
- src/lib/types.ts (1 hunks)
- src/lib/utils.ts (1 hunks)
- tailwind.config.ts (1 hunks)
- tsconfig.json (1 hunks)
Additional context used
Biome
src/lib/utils.ts
[error] 16-16: Avoid the use of spread (
...) syntax on accumulators.Spread syntax should be avoided on accumulators (like those in
.reduce) because it causes a time complexity ofO(n^2).
Consider methods such as .splice or .push instead.(lint/performance/noAccumulatingSpread)
src/app/layout.tsx
[error] 39-39: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.
Unsafe fix: Use a SelfClosingElement instead
(lint/style/useSelfClosingElements)
src/lib/queries/payments.ts
[error] 8-8: Don't use 'String' as a type.
Use lowercase primitives for consistency.
Safe fix: Use 'string' instead(lint/complexity/noBannedTypes)
src/components/request-table.tsx
[error] 81-81: Forbidden non-null assertion.
(lint/style/noNonNullAssertion)
Additional comments not posted (145)
README.md (1)
1-1: LGTM!The addition of the
<!-- @format -->comment is a good practice for ensuring consistent formatting..eslintrc.json (1)
1-3: LGTM!The ESLint configuration correctly extends
next/core-web-vitals, which is a recommended setup for Next.js projects.postcss.config.mjs (1)
1-8: LGTM!The PostCSS configuration is correctly set up with Tailwind CSS as a plugin.
src/app/requests/page.tsx (1)
1-7: LGTM!The React component is correctly implemented and renders the
RequestTablecomponent.src/lib/currency-manager.ts (1)
1-7: LGTM!The
CurrencyManageris correctly initialized with the default list.src/components/ui/skeleton.tsx (2)
1-1: LGTM!The import statement is correct and follows best practices.
3-13: LGTM!The
Skeletoncomponent is correctly implemented and follows best practices.src/lib/graphQlClient.ts (2)
3-3: LGTM!The import statement is correct and follows best practices.
5-13: Add error handling for missing environment variables.The client configuration is correct but lacks error handling for missing environment variables. Consider adding error handling to ensure the environment variables are set.
-export const graphQLClient = new GraphQLClient( - process.env.NEXT_PUBLIC_HASURA_GRAPHQL_URL || '', - { - headers: { - 'x-hasura-admin-secret': - process.env.NEXT_PUBLIC_HASURA_GRAPHQL_ADMIN_SECRET || '', - }, - }, -); +const url = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_URL; +const adminSecret = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_ADMIN_SECRET; + +if (!url) { + throw new Error('NEXT_PUBLIC_HASURA_GRAPHQL_URL is not set'); +} + +if (!adminSecret) { + throw new Error('NEXT_PUBLIC_HASURA_GRAPHQL_ADMIN_SECRET is not set'); +} + +export const graphQLClient = new GraphQLClient(url, { + headers: { + 'x-hasura-admin-secret': adminSecret, + }, +});src/components/recent-area.tsx (2)
3-4: LGTM!The import statements are correct and follow best practices.
6-13: LGTM!The
RecentAreacomponent is correctly implemented and follows best practices.src/app/page.tsx (2)
2-4: LGTM!The import statements are correct and follow best practices.
6-14: LGTM!The
Homecomponent is correctly implemented and follows best practices.components.json (1)
1-17: LGTM!The configuration settings are correct and follow best practices.
src/app/providers.tsx (2)
4-5: LGTM!The import statements are correct and follow best practices.
7-17: LGTM!The
Providerscomponent is correctly implemented and follows best practices..gitignore (3)
1-8: LGTM!The entries for ignoring dependencies are standard and necessary.
The code changes are approved.
9-15: LGTM!The entries for ignoring testing and Next.js files are standard and necessary.
The code changes are approved.
16-36: LGTM!The entries for ignoring production, misc, debug, local env files, vercel, and typescript files are standard and necessary.
The code changes are approved.
src/components/search.tsx (1)
3-5: LGTM!The import statements are necessary for the component to function correctly.
The code changes are approved.
src/components/footer.tsx (2)
3-5: LGTM!The import statements are necessary for the component to function correctly.
The code changes are approved.
7-18: LGTM!The component is well-structured and functional.
The code changes are approved.
tsconfig.json (16)
3-3: LGTM!The
liboption includes appropriate libraries for a modern web application.
4-4: LGTM!The
allowJsoption is set totrue, allowing JavaScript files to be compiled.
5-5: LGTM!The
skipLibCheckoption is set totrue, which can improve compilation speed.
6-6: LGTM!The
strictoption is set totrue, enabling all strict type-checking options.
7-7: LGTM!The
noEmitoption is set totrue, preventing the compiler from emitting output files.
8-8: LGTM!The
esModuleInteropoption is set totrue, enabling interoperability between CommonJS and ES Modules.
9-9: LGTM!The
moduleoption is set toesnext, which is appropriate for modern JavaScript environments.
10-10: LGTM!The
moduleResolutionoption is set tobundler, which is appropriate for projects using bundlers like Webpack or Rollup.
11-11: LGTM!The
resolveJsonModuleoption is set totrue, allowing importing JSON modules.
12-12: LGTM!The
isolatedModulesoption is set totrue, ensuring that each file can be safely transpiled without relying on other files.
13-13: LGTM!The
jsxoption is set topreserve, which is appropriate for projects using tools like Babel or a framework that handles JSX transformation.
14-14: LGTM!The
incrementaloption is set totrue, enabling incremental compilation to improve build performance.
15-19: LGTM!The
pluginsoption includes thenextplugin, which is appropriate for Next.js projects.
20-22: LGTM!The
pathsoption maps@/*to./src/*, simplifying imports in the project.
24-24: LGTM!The
includeoption specifies appropriate files for a Next.js project.
25-25: LGTM!The
excludeoption excludesnode_modules, which is a standard practice to improve compilation performance.src/components/search-area.tsx (2)
3-4: LGTM!The import statements are appropriate for the component.
6-23: LGTM!The
SearchAreacomponent is well-structured and follows best practices for React components.src/components/logo.tsx (2)
3-6: LGTM!The import statements are appropriate for the component.
8-33: LGTM!The
Logocomponent is well-structured and follows best practices for React components. The use of thecnutility and theImagecomponent is appropriate.src/components/header.tsx (3)
4-8: LGTM!The import statements are correct and necessary for the component.
10-11: LGTM!The component definition and
usePathnameusage are correct.
13-27: LGTM!The JSX structure is correct and follows best practices for a responsive design.
src/lib/types.ts (2)
3-23: LGTM!The
Paymentinterface is well-defined and follows TypeScript best practices.
25-36: LGTM!The
Transactioninterface is well-defined and follows TypeScript best practices.src/components/main-nav.tsx (3)
3-5: LGTM!The import statements are correct and necessary for the component.
7-11: LGTM!The component definition is correct and follows TypeScript best practices.
13-32: LGTM!The JSX structure is correct and follows best practices for a responsive design.
src/lib/utils.ts (2)
9-11: LGTM!The function
cnis correctly implemented and useful for merging class names.
22-30: LGTM!The function
formatTimestampis correctly implemented and useful for formatting timestamps.src/lib/hooks/use-latest-payments.tsx (3)
4-7: LGTM!The import statements are correct and necessary for the functionality of the custom hook.
9-12: LGTM!The
ILatestPaymentsinterface is correctly defined and improves type safety.
14-18: LGTM!The
Propstype is correctly defined and improves type safety.src/lib/queries/transactions.ts (1)
3-5: LGTM!The import statements are correct and necessary for the functionality of the file.
src/lib/apollo-wrapper.tsx (1)
4-10: LGTM!The import statements are correct and necessary for the functionality of the file.
package.json (4)
1-4: LGTM!The metadata section is correctly defined.
5-10: LGTM!The scripts section is correctly defined.
11-31: LGTM!The dependencies section is correctly defined.
32-41: LGTM!The devDependencies section is correctly defined.
src/components/ui/badge.tsx (4)
1-4: LGTM!The import statements are correctly defined.
6-24: LGTM!The badgeVariants definition is correctly defined.
26-28: LGTM!The BadgeProps interface is correctly defined.
30-34: LGTM!The Badge component is correctly defined.
src/lib/hooks/use-latest-requests.tsx (6)
1-8: LGTM!The import statements are correctly defined.
10-15: LGTM!The ILatestRequests interface is correctly defined.
17-21: LGTM!The Props type is correctly defined.
35-52: LGTM!The useMemo hook is correctly defined.
54-55: LGTM!The return statement is correctly defined.
23-32: Remove console.log statement.The hook implementation is correct, but the console.log statement should be removed in production code.
Apply this diff to remove the console.log statement:
- console.log(data);Likely invalid or redundant comment.
src/lib/consts.ts (3)
3-16: LGTM!The
CHAINSconstant is well-defined and follows best practices for defining constants.
18-31: LGTM!The
CHAIN_SCAN_URLSconstant is well-defined and follows best practices for defining constants.
33-46: LGTM!The
PAYMENT_CHAINSenum is well-defined and follows best practices for defining enums.src/components/ui/avatar.tsx (3)
8-20: LGTM!The
Avatarcomponent is well-defined and follows best practices for defining React components with forward refs.
23-33: LGTM!The
AvatarImagecomponent is well-defined and follows best practices for defining React components with forward refs.
35-47: LGTM!The
AvatarFallbackcomponent is well-defined and follows best practices for defining React components with forward refs.src/app/layout.tsx (4)
14-17: LGTM!The metadata object is well-defined and follows best practices for defining metadata in Next.js.
19-52: LGTM!The HTML structure is well-defined and follows best practices for defining the layout in Next.js.
Tools
Biome
[error] 39-39: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.
Unsafe fix: Use a SelfClosingElement instead
(lint/style/useSelfClosingElements)
6-6: LGTM!The usage of the
cnutility function is well-defined and follows best practices for applying class names in React components.Also applies to: 27-30
4-4: LGTM!The usage of the Inter font is well-defined and follows best practices for applying fonts in Next.js.
Also applies to: 12-12, 29-29
src/components/ui/button.tsx (4)
1-5: LGTM!The imports are necessary and correctly implemented.
7-34: LGTM!The
buttonVariantsconstant is correctly implemented and follows best practices for managing class names.
36-40: LGTM!The
ButtonPropsinterface is correctly implemented and provides type safety for the Button component.
42-54: LGTM!The
Buttoncomponent is correctly implemented and follows best practices for React components.src/app/globals.css (3)
1-3: LGTM!The Tailwind CSS imports are necessary and correctly implemented.
5-59: LGTM!The CSS custom properties are correctly implemented and provide a flexible theming system.
62-69: LGTM!The global element styles are correctly implemented and ensure consistent styling across the application.
src/components/ui/card.tsx (7)
1-3: LGTM!The imports are necessary and correctly implemented.
5-18: LGTM!The
Cardcomponent is correctly implemented and follows best practices for React components.
20-30: LGTM!The
CardHeadercomponent is correctly implemented and follows best practices for React components.
32-45: LGTM!The
CardTitlecomponent is correctly implemented and follows best practices for React components.
47-57: LGTM!The
CardDescriptioncomponent is correctly implemented and follows best practices for React components.
59-65: LGTM!The
CardContentcomponent is correctly implemented and follows best practices for React components.
67-77: LGTM!The
CardFootercomponent is correctly implemented and follows best practices for React components.tailwind.config.ts (9)
3-4: LGTM!The import statements are correct and necessary for the configuration.
7-13: LGTM!The
darkModeandcontentconfigurations are correct and follow best practices.
16-22: LGTM!The
containerconfigurations are correct and follow best practices.
24-57: LGTM!The
colorsextension is correct and follows best practices.
59-63: LGTM!The
borderRadiusextension is correct and follows best practices.
64-72: LGTM!The
keyframesextension is correct and follows best practices.
74-77: LGTM!The
animationextension is correct and follows best practices.
78-80: LGTM!The
fontFamilyextension is correct and follows best practices.
83-83: LGTM!The
pluginsconfiguration is correct and follows best practices.src/components/stats-area.tsx (6)
3-4: LGTM!The import statements are correct and necessary for the component.
6-8: LGTM!The grid layout is responsive and follows best practices.
9-24: LGTM!The first
Cardcomponent is correctly implemented.
25-38: LGTM!The second
Cardcomponent is correctly implemented.
39-52: LGTM!The third
Cardcomponent is correctly implemented.
53-64: LGTM!The fourth
Cardcomponent is correctly implemented.src/components/recent-request-table.tsx (5)
4-25: LGTM!The import statements are correct and necessary for the component.
27-28: LGTM!The hook usage is correct and follows best practices.
30-32: LGTM!The loading state handling is correct and follows best practices.
34-36: LGTM!The no data message handling is correct and follows best practices.
54-58: LGTM!The table header is correctly implemented.
src/components/recent-payment-table.tsx (1)
1-27: LGTM!The import statements are appropriate for the functionality provided by the component.
src/components/ui/table.tsx (9)
1-3: LGTM!The import statements are appropriate for the functionality provided by the components.
5-16: LGTM!The
Tablecomponent is well-structured and handles overflow appropriately.
19-25: LGTM!The
TableHeadercomponent is well-structured and applies the appropriate class for the header.
27-37: LGTM!The
TableBodycomponent is well-structured and applies the appropriate class for the body.
39-52: LGTM!The
TableFootercomponent is well-structured and applies the appropriate classes for the footer.
54-67: LGTM!The
TableRowcomponent is well-structured and applies the appropriate classes for the row.
69-82: LGTM!The
TableHeadcomponent is well-structured and applies the appropriate classes for the head.
84-94: LGTM!The
TableCellcomponent is well-structured and applies the appropriate classes for the cell.
96-106: LGTM!The
TableCaptioncomponent is well-structured and applies the appropriate classes for the caption.src/components/ui/sheet.tsx (11)
1-8: LGTM!The import statements are appropriate for the functionality provided by the components.
10-10: LGTM!The
Sheetcomponent is well-structured and serves its purpose as a wrapper.
12-12: LGTM!The
SheetTriggercomponent is well-structured and serves its purpose as a wrapper.
14-14: LGTM!The
SheetClosecomponent is well-structured and serves its purpose as a wrapper.
16-16: LGTM!The
SheetPortalcomponent is well-structured and serves its purpose as a wrapper.
18-31: LGTM!The
SheetOverlaycomponent is well-structured and applies the appropriate classes for the overlay.
56-75: LGTM!The
SheetContentcomponent is well-structured and applies the appropriate classes for the content.
77-89: LGTM!The
SheetHeadercomponent is well-structured and applies the appropriate classes for the header.
91-103: LGTM!The
SheetFootercomponent is well-structured and applies the appropriate classes for the footer.
105-115: LGTM!The
SheetTitlecomponent is well-structured and applies the appropriate classes for the title.
117-127: LGTM!The
SheetDescriptioncomponent is well-structured and applies the appropriate classes for the description.src/lib/queries/payments.ts (1)
8-39: LGTM!The function is correctly implemented and constructs the query string dynamically based on the
paymentChainparameter.Tools
Biome
[error] 8-8: Don't use 'String' as a type.
Use lowercase primitives for consistency.
Safe fix: Use 'string' instead(lint/complexity/noBannedTypes)
src/components/ui/dropdown-menu.tsx (8)
21-41: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
43-57: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
59-75: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
77-93: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
95-117: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
119-139: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
141-157: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
159-169: LGTM!The component is correctly implemented and follows best practices for using
React.forwardRef.
| /** @type {import('next').NextConfig} */ | ||
| const nextConfig = {}; | ||
|
|
||
| export default nextConfig; |
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.
Consider adding a comment explaining the minimal configuration.
The configuration file is correctly set up with a minimal configuration object. Adding a comment can help future developers understand that this is a placeholder for future configurations.
Apply this diff to add a comment:
/** @type {import('next').NextConfig} */
const nextConfig = {};
+// Placeholder for future Next.js configurations
export default nextConfig;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.
| /** @type {import('next').NextConfig} */ | |
| const nextConfig = {}; | |
| export default nextConfig; | |
| /** @type {import('next').NextConfig} */ | |
| const nextConfig = {}; | |
| // Placeholder for future Next.js configurations | |
| export default nextConfig; |
| export function Search() { | ||
| return ( | ||
| <div className="relative ml-auto flex-1 md:grow-0 w-full"> | ||
| {/* TODO: add / paymentReference / CID */} | ||
| <Input | ||
| type="search" | ||
| placeholder="Search by Wallet Address / Request ID" | ||
| className="pl-8 md:w-[400px] lg:w-[800px] h-12 w-full" | ||
| /> | ||
| <Button className="absolute right-2.5 top-1" size="icon"> | ||
| <SearchIcon size="20" /> | ||
| </Button> | ||
| </div> | ||
| ); |
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.
LGTM! But address the TODO comment.
The component is well-structured and functional. Ensure to address the TODO comment for additional search parameters.
The code changes are approved.
Do you want me to help with implementing the additional search parameters?
src/lib/utils.ts
Outdated
| export const groupBy = (items: any, key: any) => | ||
| items.reduce( | ||
| (result: any, item: any) => ({ | ||
| ...result, | ||
| [item[key]]: [...(result[item[key]] || []), item], | ||
| }), | ||
| {}, | ||
| ); |
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 to avoid performance issues with the spread operator.
The function correctly groups items by a specified key but has performance issues due to the spread operator. Use push instead of the spread operator.
Apply this diff to refactor the function:
-export const groupBy = (items: any, key: any) =>
- items.reduce(
- (result: any, item: any) => ({
- ...result,
- [item[key]]: [...(result[item[key]] || []), item],
- }),
- {},
- );
+export const groupBy = (items: any, key: any) =>
+ items.reduce((result: any, item: any) => {
+ (result[item[key]] = result[item[key]] || []).push(item);
+ return result;
+ }, {});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 groupBy = (items: any, key: any) => | |
| items.reduce( | |
| (result: any, item: any) => ({ | |
| ...result, | |
| [item[key]]: [...(result[item[key]] || []), item], | |
| }), | |
| {}, | |
| ); | |
| export const groupBy = (items: any, key: any) => | |
| items.reduce((result: any, item: any) => { | |
| (result[item[key]] = result[item[key]] || []).push(item); | |
| return result; | |
| }, {}); |
Tools
Biome
[error] 16-16: Avoid the use of spread (
...) syntax on accumulators.Spread syntax should be avoided on accumulators (like those in
.reduce) because it causes a time complexity ofO(n^2).
Consider methods such as .splice or .push instead.(lint/performance/noAccumulatingSpread)
| export function Socials({ color = 'black' }: { color?: string }) { | ||
| return ( | ||
| <div className="flex items-start space-x-1"> | ||
| <SocialIcon | ||
| href="https://x.com/RequestNetwork" | ||
| url="https://x.com" | ||
| fgColor={color} | ||
| bgColor="transparent" | ||
| target="_blank" | ||
| /> | ||
| <SocialIcon | ||
| href="https://www.linkedin.com/company/request-network" | ||
| url="https://www.linkedin.com" | ||
| fgColor={color} | ||
| bgColor="transparent" | ||
| target="_blank" | ||
| /> | ||
| <SocialIcon | ||
| href="https://discord.gg/FsVAR3ny3f" | ||
| url="https://discord.com" | ||
| fgColor={color} | ||
| bgColor="transparent" | ||
| target="_blank" | ||
| /> | ||
| </div> | ||
| ); |
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.
Improve prop types validation and default props.
The component is correctly implemented but can be improved by adding prop types validation and default props.
Apply this diff to add prop types validation and default props:
+import PropTypes from 'prop-types';
export function Socials({ color = 'black' }: { color?: string }) {
return (
<div className="flex items-start space-x-1">
<SocialIcon
href="https://x.com/RequestNetwork"
url="https://x.com"
fgColor={color}
bgColor="transparent"
target="_blank"
/>
<SocialIcon
href="https://www.linkedin.com/company/request-network"
url="https://www.linkedin.com"
fgColor={color}
bgColor="transparent"
target="_blank"
/>
<SocialIcon
href="https://discord.gg/FsVAR3ny3f"
url="https://discord.com"
fgColor={color}
bgColor="transparent"
target="_blank"
/>
</div>
);
}
+Socials.propTypes = {
+ color: PropTypes.string,
+};
+Socials.defaultProps = {
+ color: 'black',
+};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 function Socials({ color = 'black' }: { color?: string }) { | |
| return ( | |
| <div className="flex items-start space-x-1"> | |
| <SocialIcon | |
| href="https://x.com/RequestNetwork" | |
| url="https://x.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| <SocialIcon | |
| href="https://www.linkedin.com/company/request-network" | |
| url="https://www.linkedin.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| <SocialIcon | |
| href="https://discord.gg/FsVAR3ny3f" | |
| url="https://discord.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| </div> | |
| ); | |
| import PropTypes from 'prop-types'; | |
| export function Socials({ color = 'black' }: { color?: string }) { | |
| return ( | |
| <div className="flex items-start space-x-1"> | |
| <SocialIcon | |
| href="https://x.com/RequestNetwork" | |
| url="https://x.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| <SocialIcon | |
| href="https://www.linkedin.com/company/request-network" | |
| url="https://www.linkedin.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| <SocialIcon | |
| href="https://discord.gg/FsVAR3ny3f" | |
| url="https://discord.com" | |
| fgColor={color} | |
| bgColor="transparent" | |
| target="_blank" | |
| /> | |
| </div> | |
| ); | |
| } | |
| Socials.propTypes = { | |
| color: PropTypes.string, | |
| }; | |
| Socials.defaultProps = { | |
| color: 'black', | |
| }; |
| import * as React from "react" | ||
|
|
||
| import { cn } from "@/lib/utils" | ||
|
|
||
| export interface InputProps | ||
| extends React.InputHTMLAttributes<HTMLInputElement> {} | ||
|
|
||
| const Input = React.forwardRef<HTMLInputElement, InputProps>( | ||
| ({ className, type, ...props }, ref) => { | ||
| return ( | ||
| <input | ||
| type={type} | ||
| className={cn( | ||
| "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", | ||
| className | ||
| )} | ||
| ref={ref} | ||
| {...props} | ||
| /> | ||
| ) | ||
| } | ||
| ) | ||
| Input.displayName = "Input" | ||
|
|
||
| export { Input } |
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.
Improve prop types validation and default props.
The component is correctly implemented but can be improved by adding prop types validation and default props.
Apply this diff to add prop types validation and default props:
+import PropTypes from 'prop-types';
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
+Input.propTypes = {
+ className: PropTypes.string,
+ type: PropTypes.string,
+};
+Input.defaultProps = {
+ className: '',
+ type: 'text',
+};
export { Input }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.
| import * as React from "react" | |
| import { cn } from "@/lib/utils" | |
| export interface InputProps | |
| extends React.InputHTMLAttributes<HTMLInputElement> {} | |
| const Input = React.forwardRef<HTMLInputElement, InputProps>( | |
| ({ className, type, ...props }, ref) => { | |
| return ( | |
| <input | |
| type={type} | |
| className={cn( | |
| "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", | |
| className | |
| )} | |
| ref={ref} | |
| {...props} | |
| /> | |
| ) | |
| } | |
| ) | |
| Input.displayName = "Input" | |
| export { Input } | |
| import * as React from "react" | |
| +import PropTypes from 'prop-types'; | |
| import { cn } from "@/lib/utils" | |
| export interface InputProps | |
| extends React.InputHTMLAttributes<HTMLInputElement> {} | |
| const Input = React.forwardRef<HTMLInputElement, InputProps>( | |
| ({ className, type, ...props }, ref) => { | |
| return ( | |
| <input | |
| type={type} | |
| className={cn( | |
| "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", | |
| className | |
| )} | |
| ref={ref} | |
| {...props} | |
| /> | |
| ) | |
| } | |
| ) | |
| Input.displayName = "Input" | |
| +Input.propTypes = { | |
| + className: PropTypes.string, | |
| + type: PropTypes.string, | |
| +}; | |
| +Input.defaultProps = { | |
| + className: '', | |
| + type: 'text', | |
| +}; | |
| export { Input } |
| export function RecentPaymentTable() { | ||
| const { payments, isLoading } = useLatestPayments(); | ||
|
|
||
| if (isLoading) { | ||
| return <Skeleton className="h-full w-full rounded-xl" />; | ||
| } |
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.
Enhance Skeleton component class name.
The Skeleton component could use a more descriptive class name to indicate its purpose.
- return <Skeleton className="h-full w-full rounded-xl" />;
+ return <Skeleton className="h-full w-full rounded-xl recent-payment-skeleton" />;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 function RecentPaymentTable() { | |
| const { payments, isLoading } = useLatestPayments(); | |
| if (isLoading) { | |
| return <Skeleton className="h-full w-full rounded-xl" />; | |
| } | |
| export function RecentPaymentTable() { | |
| const { payments, isLoading } = useLatestPayments(); | |
| if (isLoading) { | |
| return <Skeleton className="h-full w-full rounded-xl recent-payment-skeleton" />; | |
| } |
| return ( | ||
| <Card className="xl:col-span-1 w-[95%] md:w-full"> | ||
| <CardHeader className="flex flex-row items-center"> | ||
| <div className="grid gap-2"> | ||
| <CardTitle>Payments</CardTitle> | ||
| <CardDescription>Recent payments.</CardDescription> | ||
| </div> | ||
| <Button asChild size="sm" className="ml-auto gap-1"> | ||
| <Link href="/payments"> | ||
| View All | ||
| <ArrowUpRight className="h-4 w-4" /> | ||
| </Link> | ||
| </Button> | ||
| </CardHeader> | ||
| <CardContent> | ||
| <Table className="overflow-x-scroll"> | ||
| <TableHeader> | ||
| <TableRow> | ||
| <TableHead>Payment Reference</TableHead> | ||
| <TableHead>Transaction Hash</TableHead> | ||
| <TableHead>Blockchain</TableHead> | ||
| <TableHead className="text-right">Timestamp</TableHead> | ||
| </TableRow> | ||
| </TableHeader> | ||
| <TableBody> | ||
| {payments.slice(0, 10).map((payment: Payment) => ( | ||
| <TableRow key={payment.id}> | ||
| <TableCell>{payment.reference.slice(0, 8)}...</TableCell> | ||
| <TableCell> | ||
| <div className="font-medium text-emerald-700"> | ||
| <Link | ||
| href={`${CHAIN_SCAN_URLS[payment.chain]}/tx/${payment.txHash}`} | ||
| target="_blank" | ||
| > | ||
| {payment.txHash.slice(0, 14)}... | ||
| </Link> | ||
| </div> | ||
| </TableCell> | ||
| <TableCell>{payment.chain}</TableCell> | ||
| <TableCell className="md:table-cell text-right"> | ||
| <TimeAgo | ||
| datetime={payment.timestamp * 1000} | ||
| locale="en_short" | ||
| />{' '} | ||
| ({formatTimestamp(payment.timestamp)}) | ||
| </TableCell> | ||
| </TableRow> | ||
| ))} | ||
| </TableBody> | ||
| </Table> | ||
| </CardContent> | ||
| </Card> |
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.
Handle empty payments array.
The table rendering logic should handle cases where payments might be an empty array.
{payments.length === 0 ? (
<div>No recent payments available.</div>
) : (
<Table className="overflow-x-scroll">
<TableHeader>
<TableRow>
<TableHead>Payment Reference</TableHead>
<TableHead>Transaction Hash</TableHead>
<TableHead>Blockchain</TableHead>
<TableHead className="text-right">Timestamp</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{payments.slice(0, 10).map((payment: Payment) => (
<TableRow key={payment.id}>
<TableCell>{payment.reference.slice(0, 8)}...</TableCell>
<TableCell>
<div className="font-medium text-emerald-700">
<Link
href={`${CHAIN_SCAN_URLS[payment.chain]}/tx/${payment.txHash}`}
target="_blank"
>
{payment.txHash.slice(0, 14)}...
</Link>
</div>
</TableCell>
<TableCell>{payment.chain}</TableCell>
<TableCell className="md:table-cell text-right">
<TimeAgo
datetime={payment.timestamp * 1000}
locale="en_short"
/>{' '}
({formatTimestamp(payment.timestamp)})
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}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.
| return ( | |
| <Card className="xl:col-span-1 w-[95%] md:w-full"> | |
| <CardHeader className="flex flex-row items-center"> | |
| <div className="grid gap-2"> | |
| <CardTitle>Payments</CardTitle> | |
| <CardDescription>Recent payments.</CardDescription> | |
| </div> | |
| <Button asChild size="sm" className="ml-auto gap-1"> | |
| <Link href="/payments"> | |
| View All | |
| <ArrowUpRight className="h-4 w-4" /> | |
| </Link> | |
| </Button> | |
| </CardHeader> | |
| <CardContent> | |
| <Table className="overflow-x-scroll"> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>Payment Reference</TableHead> | |
| <TableHead>Transaction Hash</TableHead> | |
| <TableHead>Blockchain</TableHead> | |
| <TableHead className="text-right">Timestamp</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {payments.slice(0, 10).map((payment: Payment) => ( | |
| <TableRow key={payment.id}> | |
| <TableCell>{payment.reference.slice(0, 8)}...</TableCell> | |
| <TableCell> | |
| <div className="font-medium text-emerald-700"> | |
| <Link | |
| href={`${CHAIN_SCAN_URLS[payment.chain]}/tx/${payment.txHash}`} | |
| target="_blank" | |
| > | |
| {payment.txHash.slice(0, 14)}... | |
| </Link> | |
| </div> | |
| </TableCell> | |
| <TableCell>{payment.chain}</TableCell> | |
| <TableCell className="md:table-cell text-right"> | |
| <TimeAgo | |
| datetime={payment.timestamp * 1000} | |
| locale="en_short" | |
| />{' '} | |
| ({formatTimestamp(payment.timestamp)}) | |
| </TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| </CardContent> | |
| </Card> | |
| return ( | |
| <Card className="xl:col-span-1 w-[95%] md:w-full"> | |
| <CardHeader className="flex flex-row items-center"> | |
| <div className="grid gap-2"> | |
| <CardTitle>Payments</CardTitle> | |
| <CardDescription>Recent payments.</CardDescription> | |
| </div> | |
| <Button asChild size="sm" className="ml-auto gap-1"> | |
| <Link href="/payments"> | |
| View All | |
| <ArrowUpRight className="h-4 w-4" /> | |
| </Link> | |
| </Button> | |
| </CardHeader> | |
| <CardContent> | |
| {payments.length === 0 ? ( | |
| <div>No recent payments available.</div> | |
| ) : ( | |
| <Table className="overflow-x-scroll"> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>Payment Reference</TableHead> | |
| <TableHead>Transaction Hash</TableHead> | |
| <TableHead>Blockchain</TableHead> | |
| <TableHead className="text-right">Timestamp</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {payments.slice(0, 10).map((payment: Payment) => ( | |
| <TableRow key={payment.id}> | |
| <TableCell>{payment.reference.slice(0, 8)}...</TableCell> | |
| <TableCell> | |
| <div className="font-medium text-emerald-700"> | |
| <Link | |
| href={`${CHAIN_SCAN_URLS[payment.chain]}/tx/${payment.txHash}`} | |
| target="_blank" | |
| > | |
| {payment.txHash.slice(0, 14)}... | |
| </Link> | |
| </div> | |
| </TableCell> | |
| <TableCell>{payment.chain}</TableCell> | |
| <TableCell className="md:table-cell text-right"> | |
| <TimeAgo | |
| datetime={payment.timestamp * 1000} | |
| locale="en_short" | |
| />{' '} | |
| ({formatTimestamp(payment.timestamp)}) | |
| </TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| )} | |
| </CardContent> | |
| </Card> |
src/lib/queries/payments.ts
Outdated
| import { graphQLClient } from '../graphQlClient'; | ||
| import { CHAINS, PAYMENT_CHAINS } from '../consts'; | ||
|
|
||
| export const getPaymentsQuery = (paymentChain: String) => |
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.
Use lowercase string instead of String.
Using String as a type is not recommended. The lowercase string should be used for consistency and to avoid potential issues.
Apply this diff to fix the type declaration:
-export const getPaymentsQuery = (paymentChain: String) =>
+export const getPaymentsQuery = (paymentChain: string) =>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 getPaymentsQuery = (paymentChain: String) => | |
| export const getPaymentsQuery = (paymentChain: string) => |
Tools
Biome
[error] 8-8: Don't use 'String' as a type.
Use lowercase primitives for consistency.
Safe fix: Use 'string' instead(lint/complexity/noBannedTypes)
| export const fetchPayments = async (variables: { | ||
| first: number; | ||
| skip: number; | ||
| }): Promise<Payment[]> => { | ||
| const mainnetData: { payment_mainnet: { payments: Payment[] } } = | ||
| await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.MAINNET), | ||
| variables, | ||
| ); | ||
| const arbitrumOneData: { | ||
| payment_arbitrum_one: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.ARBITRUM_ONE), | ||
| variables, | ||
| ); | ||
| const avalancheData: { | ||
| payment_avalanche: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.AVALANCHE), | ||
| variables, | ||
| ); | ||
| const bscData: { | ||
| payment_bsc: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.BSC), | ||
| variables, | ||
| ); | ||
| const celoData: { | ||
| payment_celo: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.CELO), | ||
| variables, | ||
| ); | ||
| const fantomData: { | ||
| payment_fantom: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.FANTOM), | ||
| variables, | ||
| ); | ||
| const fuseData: { | ||
| payment_fuse: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.FUSE), | ||
| variables, | ||
| ); | ||
| const maticData: { | ||
| payment_matic: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.MATIC), | ||
| variables, | ||
| ); | ||
| const moonbeamData: { | ||
| payment_moonbeam: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.MOONBEAM), | ||
| variables, | ||
| ); | ||
| const optimismData: { | ||
| payment_optimism: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.OPTIMISM), | ||
| variables, | ||
| ); | ||
| const xdaiData: { | ||
| payment_xdai: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.XDAI), | ||
| variables, | ||
| ); | ||
| const zksynceraData: { | ||
| payment_zksyncera: { payments: Payment[] }; | ||
| } = await graphQLClient.request( | ||
| getPaymentsQuery(PAYMENT_CHAINS.ZKSYNCERA), | ||
| variables, | ||
| ); | ||
|
|
||
| return mainnetData && | ||
| arbitrumOneData && | ||
| avalancheData && | ||
| bscData && | ||
| celoData && | ||
| fantomData && | ||
| fuseData && | ||
| maticData && | ||
| moonbeamData && | ||
| optimismData && | ||
| xdaiData && | ||
| zksynceraData | ||
| ? [ | ||
| ...mainnetData.payment_mainnet.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.MAINNET }; | ||
| }), | ||
| ...arbitrumOneData.payment_arbitrum_one.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.ARBITRUM_ONE }; | ||
| }), | ||
| ...avalancheData.payment_avalanche.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.AVALANCHE }; | ||
| }), | ||
| ...bscData.payment_bsc.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.BSC }; | ||
| }), | ||
| ...celoData.payment_celo.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.CELO }; | ||
| }), | ||
| ...fantomData.payment_fantom.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.FANTOM }; | ||
| }), | ||
| ...fuseData.payment_fuse.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.FUSE }; | ||
| }), | ||
| ...maticData.payment_matic.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.MATIC }; | ||
| }), | ||
| ...moonbeamData.payment_moonbeam.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.MOONBEAM }; | ||
| }), | ||
| ...optimismData.payment_optimism.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.OPTIMISM }; | ||
| }), | ||
| ...xdaiData.payment_xdai.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.XDAI }; | ||
| }), | ||
| ...zksynceraData.payment_zksyncera.payments.map((payment: any) => { | ||
| return { ...payment, chain: CHAINS.ZKSYNCERA }; | ||
| }), | ||
| ].sort((a: Payment, b: Payment) => b.timestamp - a.timestamp) | ||
| : []; |
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 to reduce redundancy and improve readability.
The function is correctly implemented but can be refactored to reduce redundancy and improve readability. Consider using a loop to iterate over the chains and fetch the data.
Apply this diff to refactor the function:
export const fetchPayments = async (variables: {
first: number;
skip: number;
}): Promise<Payment[]> => {
const chains = [
PAYMENT_CHAINS.MAINNET,
PAYMENT_CHAINS.ARBITRUM_ONE,
PAYMENT_CHAINS.AVALANCHE,
PAYMENT_CHAINS.BSC,
PAYMENT_CHAINS.CELO,
PAYMENT_CHAINS.FANTOM,
PAYMENT_CHAINS.FUSE,
PAYMENT_CHAINS.MATIC,
PAYMENT_CHAINS.MOONBEAM,
PAYMENT_CHAINS.OPTIMISM,
PAYMENT_CHAINS.XDAI,
PAYMENT_CHAINS.ZKSYNCERA,
];
const data = await Promise.all(
chains.map(async (chain) => {
const result = await graphQLClient.request(
getPaymentsQuery(chain),
variables,
);
return { chain, payments: result[`payment_${chain.toLowerCase()}`].payments };
})
);
return data
.flatMap(({ chain, payments }) =>
payments.map((payment: any) => ({ ...payment, chain: CHAINS[chain] }))
)
.sort((a: Payment, b: Payment) => b.timestamp - a.timestamp);
};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 fetchPayments = async (variables: { | |
| first: number; | |
| skip: number; | |
| }): Promise<Payment[]> => { | |
| const mainnetData: { payment_mainnet: { payments: Payment[] } } = | |
| await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.MAINNET), | |
| variables, | |
| ); | |
| const arbitrumOneData: { | |
| payment_arbitrum_one: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.ARBITRUM_ONE), | |
| variables, | |
| ); | |
| const avalancheData: { | |
| payment_avalanche: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.AVALANCHE), | |
| variables, | |
| ); | |
| const bscData: { | |
| payment_bsc: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.BSC), | |
| variables, | |
| ); | |
| const celoData: { | |
| payment_celo: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.CELO), | |
| variables, | |
| ); | |
| const fantomData: { | |
| payment_fantom: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.FANTOM), | |
| variables, | |
| ); | |
| const fuseData: { | |
| payment_fuse: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.FUSE), | |
| variables, | |
| ); | |
| const maticData: { | |
| payment_matic: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.MATIC), | |
| variables, | |
| ); | |
| const moonbeamData: { | |
| payment_moonbeam: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.MOONBEAM), | |
| variables, | |
| ); | |
| const optimismData: { | |
| payment_optimism: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.OPTIMISM), | |
| variables, | |
| ); | |
| const xdaiData: { | |
| payment_xdai: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.XDAI), | |
| variables, | |
| ); | |
| const zksynceraData: { | |
| payment_zksyncera: { payments: Payment[] }; | |
| } = await graphQLClient.request( | |
| getPaymentsQuery(PAYMENT_CHAINS.ZKSYNCERA), | |
| variables, | |
| ); | |
| return mainnetData && | |
| arbitrumOneData && | |
| avalancheData && | |
| bscData && | |
| celoData && | |
| fantomData && | |
| fuseData && | |
| maticData && | |
| moonbeamData && | |
| optimismData && | |
| xdaiData && | |
| zksynceraData | |
| ? [ | |
| ...mainnetData.payment_mainnet.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.MAINNET }; | |
| }), | |
| ...arbitrumOneData.payment_arbitrum_one.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.ARBITRUM_ONE }; | |
| }), | |
| ...avalancheData.payment_avalanche.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.AVALANCHE }; | |
| }), | |
| ...bscData.payment_bsc.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.BSC }; | |
| }), | |
| ...celoData.payment_celo.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.CELO }; | |
| }), | |
| ...fantomData.payment_fantom.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.FANTOM }; | |
| }), | |
| ...fuseData.payment_fuse.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.FUSE }; | |
| }), | |
| ...maticData.payment_matic.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.MATIC }; | |
| }), | |
| ...moonbeamData.payment_moonbeam.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.MOONBEAM }; | |
| }), | |
| ...optimismData.payment_optimism.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.OPTIMISM }; | |
| }), | |
| ...xdaiData.payment_xdai.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.XDAI }; | |
| }), | |
| ...zksynceraData.payment_zksyncera.payments.map((payment: any) => { | |
| return { ...payment, chain: CHAINS.ZKSYNCERA }; | |
| }), | |
| ].sort((a: Payment, b: Payment) => b.timestamp - a.timestamp) | |
| : []; | |
| export const fetchPayments = async (variables: { | |
| first: number; | |
| skip: number; | |
| }): Promise<Payment[]> => { | |
| const chains = [ | |
| PAYMENT_CHAINS.MAINNET, | |
| PAYMENT_CHAINS.ARBITRUM_ONE, | |
| PAYMENT_CHAINS.AVALANCHE, | |
| PAYMENT_CHAINS.BSC, | |
| PAYMENT_CHAINS.CELO, | |
| PAYMENT_CHAINS.FANTOM, | |
| PAYMENT_CHAINS.FUSE, | |
| PAYMENT_CHAINS.MATIC, | |
| PAYMENT_CHAINS.MOONBEAM, | |
| PAYMENT_CHAINS.OPTIMISM, | |
| PAYMENT_CHAINS.XDAI, | |
| PAYMENT_CHAINS.ZKSYNCERA, | |
| ]; | |
| const data = await Promise.all( | |
| chains.map(async (chain) => { | |
| const result = await graphQLClient.request( | |
| getPaymentsQuery(chain), | |
| variables, | |
| ); | |
| return { chain, payments: result[`payment_${chain.toLowerCase()}`].payments }; | |
| }) | |
| ); | |
| return data | |
| .flatMap(({ chain, payments }) => | |
| payments.map((payment: any) => ({ ...payment, chain: CHAINS[chain] })) | |
| ) | |
| .sort((a: Payment, b: Payment) => b.timestamp - a.timestamp); | |
| }; |
src/components/request-table.tsx
Outdated
| ? currencyManager.fromAddress(currencyValue) | ||
| : currencyManager.fromSymbol(currencyValue); | ||
|
|
||
| return `${formatUnits(row.original?.dataObject?.data?.parameters?.expectedAmount || '0', currencyDetails?.decimals!) || 'N/A'} ${currencyDetails?.symbol}`; |
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.
Avoid non-null assertions.
Using non-null assertions can lead to runtime errors if the value is null or undefined. Handle the case where currencyDetails might be null or undefined.
Apply this diff to handle the null or undefined case:
return `${formatUnits(
row.original?.dataObject?.data?.parameters?.expectedAmount || '0',
- currencyDetails?.decimals!
+ currencyDetails?.decimals || 18
) || 'N/A'} ${currencyDetails?.symbol}`;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.
| return `${formatUnits(row.original?.dataObject?.data?.parameters?.expectedAmount || '0', currencyDetails?.decimals!) || 'N/A'} ${currencyDetails?.symbol}`; | |
| return `${formatUnits( | |
| row.original?.dataObject?.data?.parameters?.expectedAmount || '0', | |
| currencyDetails?.decimals || 18 | |
| ) || 'N/A'} ${currencyDetails?.symbol}`; |
Tools
Biome
[error] 81-81: Forbidden non-null assertion.
(lint/style/noNonNullAssertion)
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 ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
Files selected for processing (2)
- package.json (1 hunks)
- src/components/request-table.tsx (1 hunks)
Additional context used
Biome
src/components/request-table.tsx
[error] 86-86: Forbidden non-null assertion.
(lint/style/noNonNullAssertion)
Additional comments not posted (5)
package.json (4)
1-4: LGTM!The metadata section is correctly defined.
5-10: LGTM!The scripts section is correctly defined.
11-32: LGTM!The dependencies section is correctly defined.
33-42: LGTM!The devDependencies section is correctly defined.
src/components/request-table.tsx (1)
1-33: LGTM!The imports section is correctly defined.
| export const columns: ColumnDef<Transaction>[] = [ | ||
| { | ||
| accessorKey: 'channelId', | ||
| header: 'Request Id', | ||
| cell: ({ row }) => ( | ||
| <div className="font-medium text-emerald-700"> | ||
| <Link href={`/request/${row.getValue('channelId')}`}> | ||
| {String(row.getValue('channelId')).slice(0, 20)}... | ||
| </Link> | ||
| </div> | ||
| ), | ||
| }, | ||
| { | ||
| accessorKey: 'blockTimestamp', | ||
| header: 'Timestamp', | ||
| cell: ({ row }) => ( | ||
| <div className="lowercase"> | ||
| <TimeAgo | ||
| datetime={Number(row.getValue('blockTimestamp')) * 1000} | ||
| locale="en_short" | ||
| />{' '} | ||
| ({formatTimestamp(row.getValue('blockTimestamp'))}) | ||
| </div> | ||
| ), | ||
| }, | ||
| { | ||
| accessorKey: 'payee', | ||
| header: 'Payee', | ||
| cell: ({ row }: { row: any }) => { | ||
| const address = row.original?.dataObject?.data?.parameters?.payee?.value; | ||
| return address ? truncateEthAddress(address) : 'N/A'; | ||
| }, | ||
| }, | ||
| { | ||
| accessorKey: 'payer', | ||
| header: 'Payer', | ||
| cell: ({ row }: { row: any }) => { | ||
| const address = row.original?.dataObject?.data?.parameters?.payer?.value; | ||
| return address ? truncateEthAddress(address) : 'N/A'; | ||
| }, | ||
| }, | ||
| { | ||
| accessorKey: 'expectedAmount', | ||
| header: 'Expected Amount', | ||
| cell: ({ row }: { row: any }) => { | ||
| const currencyValue = | ||
| row.original?.dataObject?.data?.parameters?.currency?.value; | ||
|
|
||
| const currencyDetails = isAddress(currencyValue) | ||
| ? currencyManager.fromAddress(currencyValue) | ||
| : currencyManager.fromSymbol(currencyValue); | ||
|
|
||
| return `${formatUnits(row.original?.dataObject?.data?.parameters?.expectedAmount || '0', currencyDetails?.decimals!) || 'N/A'} ${currencyDetails?.symbol}`; | ||
| }, | ||
| }, | ||
| ]; |
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.
Avoid non-null assertions.
Using non-null assertions can lead to runtime errors if the value is null or undefined. Handle the case where currencyDetails might be null or undefined.
Apply this diff to handle the null or undefined case:
return `${formatUnits(
row.original?.dataObject?.data?.parameters?.expectedAmount || '0',
- currencyDetails?.decimals!
+ currencyDetails?.decimals || 18
) || 'N/A'} ${currencyDetails?.symbol}`;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 columns: ColumnDef<Transaction>[] = [ | |
| { | |
| accessorKey: 'channelId', | |
| header: 'Request Id', | |
| cell: ({ row }) => ( | |
| <div className="font-medium text-emerald-700"> | |
| <Link href={`/request/${row.getValue('channelId')}`}> | |
| {String(row.getValue('channelId')).slice(0, 20)}... | |
| </Link> | |
| </div> | |
| ), | |
| }, | |
| { | |
| accessorKey: 'blockTimestamp', | |
| header: 'Timestamp', | |
| cell: ({ row }) => ( | |
| <div className="lowercase"> | |
| <TimeAgo | |
| datetime={Number(row.getValue('blockTimestamp')) * 1000} | |
| locale="en_short" | |
| />{' '} | |
| ({formatTimestamp(row.getValue('blockTimestamp'))}) | |
| </div> | |
| ), | |
| }, | |
| { | |
| accessorKey: 'payee', | |
| header: 'Payee', | |
| cell: ({ row }: { row: any }) => { | |
| const address = row.original?.dataObject?.data?.parameters?.payee?.value; | |
| return address ? truncateEthAddress(address) : 'N/A'; | |
| }, | |
| }, | |
| { | |
| accessorKey: 'payer', | |
| header: 'Payer', | |
| cell: ({ row }: { row: any }) => { | |
| const address = row.original?.dataObject?.data?.parameters?.payer?.value; | |
| return address ? truncateEthAddress(address) : 'N/A'; | |
| }, | |
| }, | |
| { | |
| accessorKey: 'expectedAmount', | |
| header: 'Expected Amount', | |
| cell: ({ row }: { row: any }) => { | |
| const currencyValue = | |
| row.original?.dataObject?.data?.parameters?.currency?.value; | |
| const currencyDetails = isAddress(currencyValue) | |
| ? currencyManager.fromAddress(currencyValue) | |
| : currencyManager.fromSymbol(currencyValue); | |
| return `${formatUnits(row.original?.dataObject?.data?.parameters?.expectedAmount || '0', currencyDetails?.decimals!) || 'N/A'} ${currencyDetails?.symbol}`; | |
| }, | |
| }, | |
| ]; | |
| export const columns: ColumnDef<Transaction>[] = [ | |
| { | |
| accessorKey: 'channelId', | |
| header: 'Request Id', | |
| cell: ({ row }) => ( | |
| <div className="font-medium text-emerald-700"> | |
| <Link href={`/request/${row.getValue('channelId')}`}> | |
| {String(row.getValue('channelId')).slice(0, 20)}... | |
| </Link> | |
| </div> | |
| ), | |
| }, | |
| { | |
| accessorKey: 'blockTimestamp', | |
| header: 'Timestamp', | |
| cell: ({ row }) => ( | |
| <div className="lowercase"> | |
| <TimeAgo | |
| datetime={Number(row.getValue('blockTimestamp')) * 1000} | |
| locale="en_short" | |
| />{' '} | |
| ({formatTimestamp(row.getValue('blockTimestamp'))}) | |
| </div> | |
| ), | |
| }, | |
| { | |
| accessorKey: 'payee', | |
| header: 'Payee', | |
| cell: ({ row }: { row: any }) => { | |
| const address = row.original?.dataObject?.data?.parameters?.payee?.value; | |
| return address ? truncateEthAddress(address) : 'N/A'; | |
| }, | |
| }, | |
| { | |
| accessorKey: 'payer', | |
| header: 'Payer', | |
| cell: ({ row }: { row: any }) => { | |
| const address = row.original?.dataObject?.data?.parameters?.payer?.value; | |
| return address ? truncateEthAddress(address) : 'N/A'; | |
| }, | |
| }, | |
| { | |
| accessorKey: 'expectedAmount', | |
| header: 'Expected Amount', | |
| cell: ({ row }: { row: any }) => { | |
| const currencyValue = | |
| row.original?.dataObject?.data?.parameters?.currency?.value; | |
| const currencyDetails = isAddress(currencyValue) | |
| ? currencyManager.fromAddress(currencyValue) | |
| : currencyManager.fromSymbol(currencyValue); | |
| return `${formatUnits(row.original?.dataObject?.data?.parameters?.expectedAmount || '0', currencyDetails?.decimals || 18) || 'N/A'} ${currencyDetails?.symbol}`; | |
| }, | |
| }, | |
| ]; |
Tools
Biome
[error] 86-86: Forbidden non-null assertion.
(lint/style/noNonNullAssertion)
| export function RequestTable() { | ||
| const [pagination, setPagination] = React.useState<PaginationState>({ | ||
| pageIndex: 0, | ||
| pageSize: 10, | ||
| }); | ||
|
|
||
| const { requests, isLoading } = useLatestRequests({ | ||
| first: pagination.pageSize, | ||
| skip: pagination.pageIndex * pagination.pageSize, | ||
| }); | ||
|
|
||
| const table = useReactTable({ | ||
| // Get only the first transaction for each request. | ||
| data: Object.values(requests).map((request) => request[0]), | ||
| columns, | ||
| pageCount: 10, | ||
| getCoreRowModel: getCoreRowModel(), | ||
| getSortedRowModel: getSortedRowModel(), | ||
| getFilteredRowModel: getFilteredRowModel(), | ||
| onPaginationChange: setPagination, | ||
| manualPagination: true, | ||
| state: { | ||
| pagination, | ||
| }, | ||
| }); | ||
|
|
||
| return ( | ||
| <div className="w-[95%] bg-white border rounded-lg self-center md:w-full"> | ||
| <div className="p-10"> | ||
| <div> | ||
| <h1 className="text-2xl font-bold">Requests</h1> | ||
| </div> | ||
| <div className="flex items-center py-4"> | ||
| <h1 className="text-sm text-muted-foreground">All requests.</h1> | ||
| </div> | ||
| <div className="rounded-md md:h-[600px]"> | ||
| <Table className="overflow-x-scroll"> | ||
| <TableHeader> | ||
| {table.getHeaderGroups().map((headerGroup) => ( | ||
| <TableRow key={headerGroup.id}> | ||
| {headerGroup.headers.map((header) => { | ||
| return ( | ||
| <TableHead key={header.id}> | ||
| {header.isPlaceholder | ||
| ? null | ||
| : flexRender( | ||
| header.column.columnDef.header, | ||
| header.getContext(), | ||
| )} | ||
| </TableHead> | ||
| ); | ||
| })} | ||
| </TableRow> | ||
| ))} | ||
| </TableHeader> | ||
| <TableBody> | ||
| {isLoading ? ( | ||
| <TableRow> | ||
| <TableCell | ||
| colSpan={columns.length} | ||
| className="h-24 text-center" | ||
| > | ||
| Loading... | ||
| </TableCell> | ||
| </TableRow> | ||
| ) : table.getRowModel().rows?.length ? ( | ||
| table.getRowModel().rows.map((row) => ( | ||
| <TableRow | ||
| key={row.id} | ||
| data-state={row.getIsSelected() && 'selected'} | ||
| > | ||
| {row.getVisibleCells().map((cell) => ( | ||
| <TableCell key={cell.id}> | ||
| {flexRender( | ||
| cell.column.columnDef.cell, | ||
| cell.getContext(), | ||
| )} | ||
| </TableCell> | ||
| ))} | ||
| </TableRow> | ||
| )) | ||
| ) : ( | ||
| <TableRow> | ||
| <TableCell | ||
| colSpan={columns.length} | ||
| className="h-24 text-center" | ||
| > | ||
| No results. | ||
| </TableCell> | ||
| </TableRow> | ||
| )} | ||
| </TableBody> | ||
| </Table> | ||
| </div> | ||
| <div className="flex items-center justify-end space-x-2 py-4"> | ||
| <div className="flex-1 text-sm text-muted-foreground"> | ||
| Page {table.getState().pagination.pageIndex + 1} | ||
| </div> | ||
| <div className="space-x-2"> | ||
| {table.getState().pagination.pageIndex > 0 && ( | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.firstPage()} | ||
| > | ||
| First | ||
| </Button> | ||
| )} | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.previousPage()} | ||
| disabled={!table.getCanPreviousPage()} | ||
| > | ||
| Previous | ||
| </Button> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={() => table.nextPage()} | ||
| disabled={!table.getCanNextPage()} | ||
| > | ||
| Next | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); |
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.
Add error handling for data fetching.
The function is correctly implemented but can be improved by adding error handling for the data fetching process. Consider adding a try-catch block around the data fetching logic and displaying an error message if the data fetching fails.
Apply this diff to add error handling:
const { requests, isLoading, error } = useLatestRequests({
first: pagination.pageSize,
skip: pagination.pageIndex * pagination.pageSize,
});
return (
<div className="w-[95%] bg-white border rounded-lg self-center md:w-full">
<div className="p-10">
<div>
<h1 className="text-2xl font-bold">Requests</h1>
</div>
<div className="flex items-center py-4">
<h1 className="text-sm text-muted-foreground">All requests.</h1>
</div>
<div className="rounded-md md:h-[600px]">
<Table className="overflow-x-scroll">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{isLoading ? (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
Loading...
</TableCell>
</TableRow>
) : error ? (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
Error loading data.
</TableCell>
</TableRow>
) : table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<div className="flex-1 text-sm text-muted-foreground">
Page {table.getState().pagination.pageIndex + 1}
</div>
<div className="space-x-2">
{table.getState().pagination.pageIndex > 0 && (
<Button
variant="outline"
size="sm"
onClick={() => table.firstPage()}
>
First
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
</div>
</div>
);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 function RequestTable() { | |
| const [pagination, setPagination] = React.useState<PaginationState>({ | |
| pageIndex: 0, | |
| pageSize: 10, | |
| }); | |
| const { requests, isLoading } = useLatestRequests({ | |
| first: pagination.pageSize, | |
| skip: pagination.pageIndex * pagination.pageSize, | |
| }); | |
| const table = useReactTable({ | |
| // Get only the first transaction for each request. | |
| data: Object.values(requests).map((request) => request[0]), | |
| columns, | |
| pageCount: 10, | |
| getCoreRowModel: getCoreRowModel(), | |
| getSortedRowModel: getSortedRowModel(), | |
| getFilteredRowModel: getFilteredRowModel(), | |
| onPaginationChange: setPagination, | |
| manualPagination: true, | |
| state: { | |
| pagination, | |
| }, | |
| }); | |
| return ( | |
| <div className="w-[95%] bg-white border rounded-lg self-center md:w-full"> | |
| <div className="p-10"> | |
| <div> | |
| <h1 className="text-2xl font-bold">Requests</h1> | |
| </div> | |
| <div className="flex items-center py-4"> | |
| <h1 className="text-sm text-muted-foreground">All requests.</h1> | |
| </div> | |
| <div className="rounded-md md:h-[600px]"> | |
| <Table className="overflow-x-scroll"> | |
| <TableHeader> | |
| {table.getHeaderGroups().map((headerGroup) => ( | |
| <TableRow key={headerGroup.id}> | |
| {headerGroup.headers.map((header) => { | |
| return ( | |
| <TableHead key={header.id}> | |
| {header.isPlaceholder | |
| ? null | |
| : flexRender( | |
| header.column.columnDef.header, | |
| header.getContext(), | |
| )} | |
| </TableHead> | |
| ); | |
| })} | |
| </TableRow> | |
| ))} | |
| </TableHeader> | |
| <TableBody> | |
| {isLoading ? ( | |
| <TableRow> | |
| <TableCell | |
| colSpan={columns.length} | |
| className="h-24 text-center" | |
| > | |
| Loading... | |
| </TableCell> | |
| </TableRow> | |
| ) : table.getRowModel().rows?.length ? ( | |
| table.getRowModel().rows.map((row) => ( | |
| <TableRow | |
| key={row.id} | |
| data-state={row.getIsSelected() && 'selected'} | |
| > | |
| {row.getVisibleCells().map((cell) => ( | |
| <TableCell key={cell.id}> | |
| {flexRender( | |
| cell.column.columnDef.cell, | |
| cell.getContext(), | |
| )} | |
| </TableCell> | |
| ))} | |
| </TableRow> | |
| )) | |
| ) : ( | |
| <TableRow> | |
| <TableCell | |
| colSpan={columns.length} | |
| className="h-24 text-center" | |
| > | |
| No results. | |
| </TableCell> | |
| </TableRow> | |
| )} | |
| </TableBody> | |
| </Table> | |
| </div> | |
| <div className="flex items-center justify-end space-x-2 py-4"> | |
| <div className="flex-1 text-sm text-muted-foreground"> | |
| Page {table.getState().pagination.pageIndex + 1} | |
| </div> | |
| <div className="space-x-2"> | |
| {table.getState().pagination.pageIndex > 0 && ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.firstPage()} | |
| > | |
| First | |
| </Button> | |
| )} | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.previousPage()} | |
| disabled={!table.getCanPreviousPage()} | |
| > | |
| Previous | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.nextPage()} | |
| disabled={!table.getCanNextPage()} | |
| > | |
| Next | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| export function RequestTable() { | |
| const [pagination, setPagination] = React.useState<PaginationState>({ | |
| pageIndex: 0, | |
| pageSize: 10, | |
| }); | |
| const { requests, isLoading, error } = useLatestRequests({ | |
| first: pagination.pageSize, | |
| skip: pagination.pageIndex * pagination.pageSize, | |
| }); | |
| const table = useReactTable({ | |
| // Get only the first transaction for each request. | |
| data: Object.values(requests).map((request) => request[0]), | |
| columns, | |
| pageCount: 10, | |
| getCoreRowModel: getCoreRowModel(), | |
| getSortedRowModel: getSortedRowModel(), | |
| getFilteredRowModel: getFilteredRowModel(), | |
| onPaginationChange: setPagination, | |
| manualPagination: true, | |
| state: { | |
| pagination, | |
| }, | |
| }); | |
| return ( | |
| <div className="w-[95%] bg-white border rounded-lg self-center md:w-full"> | |
| <div className="p-10"> | |
| <div> | |
| <h1 className="text-2xl font-bold">Requests</h1> | |
| </div> | |
| <div className="flex items-center py-4"> | |
| <h1 className="text-sm text-muted-foreground">All requests.</h1> | |
| </div> | |
| <div className="rounded-md md:h-[600px]"> | |
| <Table className="overflow-x-scroll"> | |
| <TableHeader> | |
| {table.getHeaderGroups().map((headerGroup) => ( | |
| <TableRow key={headerGroup.id}> | |
| {headerGroup.headers.map((header) => { | |
| return ( | |
| <TableHead key={header.id}> | |
| {header.isPlaceholder | |
| ? null | |
| : flexRender( | |
| header.column.columnDef.header, | |
| header.getContext(), | |
| )} | |
| </TableHead> | |
| ); | |
| })} | |
| </TableRow> | |
| ))} | |
| </TableHeader> | |
| <TableBody> | |
| {isLoading ? ( | |
| <TableRow> | |
| <TableCell | |
| colSpan={columns.length} | |
| className="h-24 text-center" | |
| > | |
| Loading... | |
| </TableCell> | |
| </TableRow> | |
| ) : error ? ( | |
| <TableRow> | |
| <TableCell | |
| colSpan={columns.length} | |
| className="h-24 text-center" | |
| > | |
| Error loading data. | |
| </TableCell> | |
| </TableRow> | |
| ) : table.getRowModel().rows?.length ? ( | |
| table.getRowModel().rows.map((row) => ( | |
| <TableRow | |
| key={row.id} | |
| data-state={row.getIsSelected() && 'selected'} | |
| > | |
| {row.getVisibleCells().map((cell) => ( | |
| <TableCell key={cell.id}> | |
| {flexRender( | |
| cell.column.columnDef.cell, | |
| cell.getContext(), | |
| )} | |
| </TableCell> | |
| ))} | |
| </TableRow> | |
| )) | |
| ) : ( | |
| <TableRow> | |
| <TableCell | |
| colSpan={columns.length} | |
| className="h-24 text-center" | |
| > | |
| No results. | |
| </TableCell> | |
| </TableRow> | |
| )} | |
| </TableBody> | |
| </Table> | |
| </div> | |
| <div className="flex items-center justify-end space-x-2 py-4"> | |
| <div className="flex-1 text-sm text-muted-foreground"> | |
| Page {table.getState().pagination.pageIndex + 1} | |
| </div> | |
| <div className="space-x-2"> | |
| {table.getState().pagination.pageIndex > 0 && ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.firstPage()} | |
| > | |
| First | |
| </Button> | |
| )} | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.previousPage()} | |
| disabled={!table.getCanPreviousPage()} | |
| > | |
| Previous | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={() => table.nextPage()} | |
| disabled={!table.getCanNextPage()} | |
| > | |
| Next | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); |
4f78ec2 to
a880d89
Compare
|
|
||
| const inter = Inter({ subsets: ['latin'], variable: '--font-sans' }); | ||
|
|
||
| export const metadata: Metadata = { |
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.
We should change the metadata to show Request Checkout
681b2d2 to
bb8bcb7
Compare
bb8bcb7 to
9e5bcf2
Compare
9e5bcf2 to
96d33bb
Compare
Resolves #9
Summary by CodeRabbit
New Features
.gitignorefile to streamline version control by excluding unnecessary files.ApolloWrappercomponent for integrating Apollo Client in the application.Bug Fixes
Documentation
Chores