Skip to content
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

Display user's shared links table + Add new links #64

Merged

Conversation

amalessid
Copy link
Collaborator

@amalessid amalessid commented Sep 16, 2024

Note : Currently working with mock data
image

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced a LinksTable component to display shared links with pagination and formatted data.
    • Added an AddLinkDialog for creating new shareable links through a user-friendly interface.
    • Implemented a new environment variable NEXT_PUBLIC_API_URL for enhanced API configuration.
    • Integrated react-hook-form for improved form management.

These enhancements improve user experience by providing direct access to important features and organizing shared links effectively.

@amalessid amalessid self-assigned this Sep 16, 2024
@amalessid amalessid linked an issue Sep 16, 2024 that may be closed by this pull request
3 tasks
Copy link

coderabbitai bot commented Sep 16, 2024

Walkthrough

The changes introduce a new AddLinkDialog component for creating shareable links and a LinksTable component for displaying shared links with pagination and formatted data. Additionally, an Api class is defined for handling HTTP requests, and new environment variables are added to the configuration files for API endpoint management. The modifications enhance the application's ability to manage and display shared links effectively.

Changes

Files Change Summary
.env, .env.example Added new variable NEXT_PUBLIC_API_URL=${NEXTAUTH_URL}/api/v1 for public API URL configuration.
src/app/shared-links/Components/AddLinkDialog.tsx, src/app/shared-links/Components/LinksTable.tsx Introduced AddLinkDialog component for creating new shareable links and LinksTable for displaying shared links.
src/app/utils/api.class.ts Introduced BaseApi and ApiSHLink classes for handling HTTP requests with CRUD methods.
src/app/utils/api.types.ts Added IApiProps interface and EEndpoint enum for API-related properties.
package.json Updated axios version from ^1.7.5 to ^1.7.7 and added react-hook-form dependency.
envConfig.ts Introduced new file for loading environment variables.

Possibly related PRs

  • Feat/api authentication #45: The changes in this PR involve the introduction of a new authentication configuration using Keycloak, which relates to the addition of the NEXT_PUBLIC_API_URL environment variable in the main PR, as both are focused on enhancing the application's API and authentication capabilities.
  • Fix/docker image build for production #52: This PR includes updates to the .env file, which also contains the NEXTAUTH_URL variable. The changes in both PRs are related to environment configuration for authentication and API endpoints.

Suggested reviewers

  • BMartinos
  • godchiSymbionix

Poem

In the table, links do shine,
With expiry dates and passcodes fine.
A page for sharing, neat and bright,
Users can hop in with delight!
So gather 'round, come take a look,
A world of links in our new book! 🐇✨


Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e9d0d34 and 0616346.

Files selected for processing (3)
  • src/app/shared-links/Components/AddLinkDialog.tsx (1 hunks)
  • src/app/shared-links/Components/LinksTable.tsx (1 hunks)
  • src/app/utils/api.class.ts (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • src/app/shared-links/Components/AddLinkDialog.tsx
  • src/app/shared-links/Components/LinksTable.tsx
  • src/app/utils/api.class.ts

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?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    -- I pushed a fix in commit <commit_id>, please review it.
    -- Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    -- @coderabbitai generate unit testing code for this file.
    -- @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    -- @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    -- @coderabbitai read src/utils.ts and generate unit testing code.
    -- @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    -- @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Outside diff range and nitpick comments (1)
src/app/shared-links/LinksTable.tsx (1)

49-85: Consider moving the mock data to a separate file.

The apiDataMock constant provides a good representation of the expected data structure, and the rows constant is created correctly by mapping the mock data using the createData function.

However, as the component grows, it might be beneficial to move the mock data to a separate file (e.g., mockData.ts) to keep the component file focused on the UI logic and improve maintainability.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 0ec76f8 and 82bee82.

Files selected for processing (3)
  • src/app/components/Header.tsx (1 hunks)
  • src/app/shared-links/LinksTable.tsx (1 hunks)
  • src/app/shared-links/page.tsx (1 hunks)
Additional comments not posted (7)
src/app/shared-links/page.tsx (2)

1-3: LGTM!

The imports are correctly used for layout, styling, and rendering the links data.


16-16: LGTM!

Rendering the LinksTable component inside the Container is appropriate for displaying the shared links data. It keeps the SharedLinksPage component focused on layout and styling, while delegating the data fetching and rendering to the LinksTable component.

src/app/components/Header.tsx (1)

43-45: LGTM!

The new "Dashboard" menu item is correctly implemented and enhances the navigation options in the header menu. The MenuItem component is properly configured with the necessary props, and the label accurately reflects the purpose of the link. This addition improves the user experience by providing direct access to the dashboard.

src/app/shared-links/LinksTable.tsx (4)

1-23: LGTM!

The imports and type definitions are appropriate and well-structured.


25-47: LGTM!

The columns constant and createData function are well-defined and serve their purposes effectively.


86-99: LGTM!

The component's state and event handlers are implemented correctly to manage the pagination functionality of the table.


101-151: LGTM!

The LinksTable component's rendering logic is well-structured and follows the Material-UI table components' API correctly. The use of map functions to render the table header and body based on the columns and rows data is efficient and readable. The pagination functionality is correctly integrated with the TablePagination component, allowing users to navigate through the data.

src/app/shared-links/page.tsx Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a 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

Outside diff range and nitpick comments (1)
src/app/shared-links/Components/LinksTable.tsx (1)

58-90: TODO: Replace the mock data with real data from an API.

The table is currently using mock data, which is fine for testing and development purposes. However, before releasing this feature to production, the mock data should be replaced with real data fetched from an API.

Do you want me to open a GitHub issue to track this task?

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e683626 and 734e8d7.

Files selected for processing (3)
  • src/app/shared-links/Components/BooleanIcon.tsx (1 hunks)
  • src/app/shared-links/Components/LinksTable.tsx (1 hunks)
  • src/app/shared-links/page.tsx (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/app/shared-links/page.tsx
Additional comments not posted (2)
src/app/shared-links/Components/BooleanIcon.tsx (1)

5-15: LGTM!

The BooleanIcon component is well-implemented and follows best practices:

  • It correctly renders the appropriate icon based on the boolean status prop.
  • It uses a concise and readable ternary operator to conditionally render the icons.
  • It uses the Material-UI colors to style the icons, maintaining consistency with the Material-UI theme.
  • It has a clear and descriptive name that conveys its purpose.
  • It has a clear and descriptive prop type definition.
  • It returns a JSX element, which is the expected return type for a React component.
src/app/shared-links/Components/LinksTable.tsx (1)

94-157: LGTM! The LinksTable component is a good starting point for the shared links feature.

The component is well-structured and uses Material-UI components effectively for styling and layout. The pagination functionality is also implemented correctly.

src/app/shared-links/Components/LinksTable.tsx Outdated Show resolved Hide resolved
Copy link
Collaborator

@yassinedorbozgithub yassinedorbozgithub left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@BMartinos
Copy link
Collaborator

@amalessid overall looks great 👍
Just one additional request (just thinking of this now seeing the attached screenshot), Can we somehow indicate if a link is active or not? I think we get the link status back which indicates if its still active or not.

Either we can have another column which defines the status, or maybe we can do some kind of color code? or maybe grey out the inactive ones to indicate its inactive?

@amalessid
Copy link
Collaborator Author

n do some kind of color code? or maybe grey out the inactive ones to indicate its inactive?

@amalessid overall looks great 👍 Just one additional request (just thinking of this now seeing the attached screenshot), Can we somehow indicate if a link is active or not? I think we get the link status back which indicates if its still active or not.

Either we can have another column which defines the status, or maybe we can do some kind of color code? or maybe grey out the inactive ones to indicate its inactive?

Yes, I agree. Link's status is definitely important in this scope. I'll be adding that.

@yassinedorbozgithub yassinedorbozgithub marked this pull request as draft September 19, 2024 13:35
@yassinedorbozgithub yassinedorbozgithub marked this pull request as ready for review September 20, 2024 08:25
Copy link

@coderabbitai coderabbitai bot left a 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

Outside diff range and nitpick comments (3)
src/app/utils/api.class.ts (1)

8-12: Consider using a more specific type for AxiosRequestConfig.

Instead of using any for the AxiosRequestConfig type, consider using a more specific type to improve type safety. This will help catch potential type-related issues at compile time.

src/app/shared-links/Components/LinksTable.tsx (2)

64-155: Consider adding sorting, filtering, and searching capabilities to the table.

To enhance the user experience and make it easier to find specific shared links, consider implementing the following features:

  • Sorting: Allow users to sort the table by clicking on the column headers.
  • Filtering: Allow users to filter the table by specific criteria, such as expiry date or passcode enabled.
  • Searching: Allow users to search for specific shared links by name or URL.

64-155: Consider making the table responsive for smaller screens.

The table may not look good on smaller screens, such as mobile devices. Consider using Material-UI's responsive table components or implementing custom styles to make the table more mobile-friendly.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 734e8d7 and 8565d0a.

Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
Files selected for processing (6)
  • package.json (1 hunks)
  • src/app/hooks/useSession.ts (1 hunks)
  • src/app/shared-links/Components/AddLinkDialog.tsx (1 hunks)
  • src/app/shared-links/Components/LinksTable.tsx (1 hunks)
  • src/app/shared-links/page.tsx (1 hunks)
  • src/app/utils/api.class.ts (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/app/shared-links/page.tsx
Additional context used
Biome
src/app/shared-links/Components/AddLinkDialog.tsx

[error] 17-17: Don't use 'Object' as a type.

Prefer explicitly define the object shape. This type means "any non-nullable value", which is slightly better than 'unknown', but it's still a broad type.

(lint/complexity/noBannedTypes)

Additional comments not posted (10)
src/app/hooks/useSession.ts (1)

1-19: LGTM!

The custom useSession hook is a clean and reusable way to manage the session state in the application. It encapsulates the session fetching logic using the getSession function from next-auth/react and stores the fetched session in the component state using the useState hook.

The fetchSession function is memoized using the useCallback hook to avoid unnecessary re-creation on re-renders, which is a good optimization. The useEffect hook is used to fetch the session when the component mounts, ensuring that the session is available when the component is rendered.

The hook returns the session state, allowing consuming components to easily access the session data.

Overall, the implementation is clean, efficient, and promotes code reusability.

src/app/utils/api.class.ts (3)

14-19: LGTM!

The Api class and its create method are implemented correctly. The constructor sets the request property as protected, and the create method provides a convenient way to make POST requests with the provided url, data, and params.


21-31: LGTM!

The find, update, and delete methods in the Api class are implemented correctly. The use of Omit ensures that the data property is not required for the find and delete methods, and the corresponding HTTP methods are used correctly.


34-34: LGTM!

Exporting an instance of the Api class as apiClient is a good practice. It allows other parts of the application to use the API client without having to create a new instance each time.

package.json (1)

27-27: Verify compatibility and behavior of the updated axios package.

The minor version update to the axios package from ^1.7.5 to ^1.7.7 is unlikely to introduce breaking changes. However, it's important to ensure that the update does not introduce any unexpected behavior or compatibility issues with other parts of the codebase.

Run the following script to verify the axios package usage and compatibility:

Verification successful

Axios usage confirmed. Update approved with testing recommendation.

The axios package is indeed used in the project, with imports and usage found in multiple files:

  • src/services/base-service.service.ts
  • src/app/utils/api.class.ts
  • src/app/shared-links/Components/LinksTable.tsx

The minor version update from 1.7.5 to 1.7.7 is unlikely to cause issues with the current usage. However, it's always a good practice to test the application after updating dependencies to ensure full compatibility.

  • Run your test suite to verify that all axios-related functionality works as expected with the new version.
  • Manually test any features that involve API calls or use axios directly.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify `axios` package usage and compatibility.

# Test 1: Search for `axios` imports. Expect: Only valid imports from the `axios` package.
rg --type typescript $'import .* from \'axios\''

# Test 2: Search for `axios` usage. Expect: Only valid usage of `axios` methods and properties.
rg --type typescript -A 5 $'axios\.'

Length of output: 161


Script:

#!/bin/bash
# Description: Verify `axios` package usage and compatibility.

# Find all JavaScript and TypeScript files
echo "JavaScript and TypeScript files:"
fd -e js -e jsx -e ts -e tsx

# Search for axios imports
echo -e "\nAxios imports:"
fd -e js -e jsx -e ts -e tsx | xargs rg 'import .* from [\'"]axios[\'"]'

# Search for axios usage with more context
echo -e "\nAxios usage:"
fd -e js -e jsx -e ts -e tsx | xargs rg -A 10 'axios\.'

Length of output: 8267


Script:

#!/bin/bash
# Description: Verify `axios` package usage and compatibility (attempt 2).

# Search for axios imports
echo "Axios imports:"
rg "import.*from ['\"]axios['\"]" --type js --type ts --type jsx --type tsx

# Search for axios usage with context
echo -e "\nAxios usage:"
rg "axios\." -A 5 --type js --type ts --type jsx --type tsx

Length of output: 279


Script:

#!/bin/bash
# Description: Final attempt to verify `axios` package usage and compatibility.

# Search for axios imports without specifying file types
echo "Axios imports:"
rg "import.*from ['\"]axios['\"]"

# Search for axios usage without specifying file types
echo -e "\nAxios usage:"
rg "axios\." -A 5

Length of output: 1590

src/app/shared-links/Components/AddLinkDialog.tsx (4)

1-16: LGTM!

The imports are well-organized and follow a consistent structure. The necessary dependencies from React, Material-UI, custom hooks, and utilities are imported correctly.


20-36: LGTM!

The styled components for the dialog title, content, and actions are created using the styled function from Material-UI. The styles are applied consistently and follow a similar pattern for each component.


38-48: LGTM!

The createSHLink function is implemented correctly, making an API call to create a shared link using the provided url and data. The optional callback function is invoked after a successful API call.

The TCreateSHLinkDto type is a valid extension of CreateSHLinkDto with an optional configExp property.


50-127: LGTM!

The AddLinkDialog component is implemented correctly:

  • It uses the useSession hook to retrieve user data for the read-only user ID field.
  • The form state is managed using the useState hook and the payload state variable.
  • The handleChange function updates the payload state based on form input changes.
  • The dialog is rendered with the necessary form fields, including user ID, name, PIN code, and expiration date.
  • The "Create" button triggers the createSHLink function with the form data and invokes the callback and onClose functions.
src/app/shared-links/Components/LinksTable.tsx (1)

64-155: LGTM!

The LinksTable component is well-implemented and follows the best practices for React components. It uses the Material-UI components, which are well-tested and accessible. It also uses the useSession hook to keep the data in sync with the session, and the useEffect hook to fetch the data when the user's ID changes. The component is modular and reusable, and it uses the useState hook to manage the state of the pagination and the dialog. The component is also using the axios library to make the API request, which is a good choice for a simple API request. The component is using the SHLinkMiniDto interface to type the data, which is a good way to keep the data typed and avoid runtime errors. The component is using the BooleanIcon component to display the boolean values, which is a good way to keep the table readable and accessible. The component is using the CalendarTodayIcon component to display the expiry date, which is a good way to keep the table readable and accessible. The component is using the Paper component to wrap the table, which is a good way to keep the table responsive and accessible. The component is using the Grid component to align the button to the right, which is a good way to keep the layout responsive and accessible. The component is using the TableContainer component to set a max height for the table, which is a good way to keep the table responsive and accessible. The component is using the TableHead component to display the table headers, which is a good way to keep the table readable and accessible. The component is using the TableBody component to display the table rows, which is a good way to keep the table readable and accessible. The component is using the TableRow component to display the table rows, which is a good way to keep the table readable and accessible. The component is using the TableCell component to display the table cells, which is a good way to keep the table readable and accessible. The component is using the TablePagination component to display the pagination, which is a good way to keep the table readable and accessible. The component is using the Button component to display the button, which is a good way to keep the button accessible. The component is using the sx prop to set the styles, which is a good way to keep the styles local to the component. The component is using the aria-label prop to set the accessibility label, which is a good way to keep the table accessible. The component is using the tabIndex prop to set the tab index, which is a good way to keep the table accessible. The component is using the hover prop to set the hover effect, which is a good way to keep the table readable and accessible. The component is using the key prop to set the key for the table rows, which is a good way to keep the table performant. The component is using the align prop to set the alignment for the table cells, which is a good way to keep the table readable and accessible. The component is using the style prop to set the styles for the table cells, which is a good way to keep the styles local to the component. The component is using the rowsPerPageOptions prop to set the options for the pagination, which is a good way to keep the pagination readable and accessible. The component is using the component prop to set the component for the pagination, which is a good way to keep the pagination accessible. The component is using the count prop to set the total number of rows for the pagination, which is a good way to keep the pagination readable and accessible. The component is using the rowsPerPage prop to set the number of rows per page for the pagination, which is a good way to keep the pagination readable and accessible. The component is using the page prop to set the current page for the pagination, which is a good way to keep the pagination readable and accessible. The component is using the onPageChange prop to set the callback for the page change for the pagination, which is a good way to keep the pagination readable and accessible. The component is using the onRowsPerPageChange prop to set the callback for the rows per page change for the pagination, which is a good way to keep the pagination readable and accessible.

Comment on lines 3 to 6
const instance = axios.create({
baseURL: 'http://localhost:3000',
withCredentials: true,
});
Copy link

Choose a reason for hiding this comment

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

Consider using environment variables for the base URL and ensure CSRF protection.

Please consider the following suggestions:

  • Use environment variables to set the base URL based on the deployment environment. Hardcoding the base URL could lead to issues when deploying the application to different environments.
  • Ensure that proper CSRF protection measures are in place when using withCredentials. Enabling withCredentials without proper security measures could expose the application to CSRF attacks.

@amalessid amalessid changed the title Display user's shared links table Display user's shared links table + Add new links Sep 20, 2024
@yassinedorbozgithub yassinedorbozgithub linked an issue Sep 20, 2024 that may be closed by this pull request
@yassinedorbozgithub yassinedorbozgithub force-pushed the 61-show-user-shared-links-in-material-ui-tab-structure branch from eb142ea to 05e3e9b Compare September 20, 2024 15:33
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios';

const instance = axios.create({
baseURL: 'http://localhost:3000/api/v1',
Copy link
Collaborator

Choose a reason for hiding this comment

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

perhaps let's make this an environment variable which is substitutable at runtime. We can follow this article as a reference https://blog.innei.ren/nextjs-runtime-env-and-build-once-deploy-many?locale=en.

params?: AxiosRequestConfig<any>;
}

class Api {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we can make this as a base class and make service specifics classes for shlinks, shlink-endpoints, etc so that we do not need to pass the url in the components. This will also help with refactoring should we look to use different endpoint names in future

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's a good idea 🚀

}
}

export const apiClient = new Api(instance);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we not define an interceptor that populates the bearer token before sending a request?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The cookies set it after the login allow us to interact with the API endpoints without the bearer token

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Outside diff range and nitpick comments (3)
src/app/utils/api.types.ts (1)

3-7: LGTM: Well-structured IApiProps interface with a minor suggestion

The IApiProps interface is well-defined with appropriate required and optional properties for API requests. However, consider using a more specific type instead of any for AxiosRequestConfig<any> to improve type safety.

Consider replacing AxiosRequestConfig<any> with a more specific type if possible, e.g., AxiosRequestConfig<object> or a custom type that fits your use case. This will provide better type checking and reduce the risk of runtime errors.

.env.example (1)

19-19: LGTM! Consider adding a comment for clarity.

The addition of NEXT_PUBLIC_API_URL is appropriate and aligns with the PR objectives. It provides a configurable API endpoint that will be useful for implementing the shared links feature.

Consider adding a brief comment above this line to explain its purpose:

+# API endpoint for client-side requests
NEXT_PUBLIC_API_URL=${NEXTAUTH_URL}/api/v1

This will help other developers understand the intended use of this variable.

.env (1)

19-19: LGTM! Consider adding a comment for clarity.

The addition of NEXT_PUBLIC_API_URL is a good approach for centralizing the API endpoint configuration. It correctly uses the NEXTAUTH_URL as a base, ensuring consistency with the authentication setup.

Consider adding a brief comment above this line to explain its purpose:

+# Public API URL for client-side requests
NEXT_PUBLIC_API_URL=${NEXTAUTH_URL}/api/v1

This will help other developers quickly understand the intention behind this environment variable.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 05e3e9b and e9d0d34.

Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
Files selected for processing (8)
  • .env (1 hunks)
  • .env.example (1 hunks)
  • envConfig.ts (1 hunks)
  • package.json (1 hunks)
  • src/app/shared-links/Components/AddLinkDialog.tsx (1 hunks)
  • src/app/shared-links/Components/LinksTable.tsx (1 hunks)
  • src/app/utils/api.class.ts (1 hunks)
  • src/app/utils/api.types.ts (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/app/shared-links/Components/LinksTable.tsx
Additional context used
Biome
src/app/shared-links/Components/AddLinkDialog.tsx

[error] 18-18: Don't use 'Object' as a type.

Prefer explicitly define the object shape. This type means "any non-nullable value", which is slightly better than 'unknown', but it's still a broad type.

(lint/complexity/noBannedTypes)

Additional comments not posted (7)
src/app/utils/api.types.ts (3)

1-1: LGTM: Correct import of AxiosRequestConfig type

The import statement is correctly using the type keyword for a type-only import from the 'axios' library, which is a good TypeScript practice.


1-11: Overall, well-structured API types with room for minor improvements

The api.types.ts file introduces well-defined types for API interactions, which aligns with the PR objectives of implementing a feature to display and add shared links. The use of TypeScript interfaces and enums provides a good foundation for type-safe API calls.

Consider the following improvements:

  1. Use more specific types instead of any where possible.
  2. Standardize naming conventions, especially for enum members.
  3. As the application grows, ensure to add other endpoints to the EEndpoint enum or consider splitting endpoints into separate enums if they become numerous.

These types will contribute to a more robust and maintainable codebase as you implement the shared links feature.


9-11: LGTM: EEndpoint enum with suggestions for improvement

The use of an enum for endpoints is a good practice. However, there are a few points to consider:

  1. The enum currently contains only one endpoint. If this is intentional for the current feature, that's fine, but ensure to add other endpoints as the application grows.

  2. The naming convention for the enum member uses camelCase ('shareLinks'), which is unconventional in TypeScript. Consider using PascalCase for enum members.

Consider updating the enum member to use PascalCase:

export enum EEndpoint {
  ShareLinks = 'share-links',
}

To ensure consistency across the codebase, let's check for other potential endpoint definitions:

Verification successful

LGTM: EEndpoint enum with minor suggestions

The use of an enum for endpoints is appropriate. Currently, only one endpoint is defined.

Suggestions:

  1. Naming Convention: The enum member shareLinks uses camelCase, which is unconventional in TypeScript. Consider renaming it to PascalCase for consistency.

    export enum EEndpoint {
      ShareLinks = 'share-links',
    }
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other endpoint definitions or usages
rg --type typescript -i '(enum|const).*endpoint'

Length of output: 85


Script:

#!/bin/bash
# Corrected search for other endpoint definitions or usages in TypeScript files
rg -i '(enum|const).*endpoint' --glob '*.ts' --glob '*.tsx'

Length of output: 3784

src/app/utils/api.class.ts (2)

1-47: Overall implementation looks great with room for minor enhancements.

The API handling implementation in this file is well-structured and addresses many of the concerns raised in previous comments. Here's a summary of the strengths and areas for potential improvement:

Strengths:

  1. Use of environment variables for the base URL.
  2. Implementation of a base API class with derived service-specific classes.
  3. Use of TypeScript for improved type safety.
  4. Consistent method signatures and naming conventions.

Areas for potential enhancement:

  1. Implement CSRF protection measures.
  2. Add error handling and request/response interceptors.
  3. Use more specific types for method parameters (e.g., in createLink).
  4. Consider a factory function for the exported API instance to facilitate testing.

Overall, this is a solid foundation for API interactions in the application. Addressing the suggested enhancements will further improve the robustness and maintainability of the code.


1-9: Approve use of environment variables for base URL and suggest CSRF protection.

Great job on using environment variables for the base URL. This addresses the previous comment about making it configurable for different environments.

However, as mentioned in a past comment, ensure that proper CSRF protection measures are in place, especially when using withCredentials (which isn't visible in this file but might be used elsewhere).

To verify CSRF protection implementation, run the following script:

src/app/shared-links/Components/AddLinkDialog.tsx (2)

21-37: Styled components look good

The styled components for the dialog title, content, and actions are well-defined and provide a consistent custom appearance for the dialog.


39-47: Type definitions are well-structured

The TCreateSHLinkDto type and AddLinkDialogProps interface are well-defined and provide clear type information for the component.

Comment on lines +1 to +4
import { loadEnvConfig } from '@next/env';

const projectDir = process.cwd();
loadEnvConfig(projectDir);
Copy link

Choose a reason for hiding this comment

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

Add error handling and logging.

While the current implementation is functional, it doesn't handle potential errors or provide any logging. This could make debugging issues related to environment configuration more difficult.

Consider adding error handling and logging:

import { loadEnvConfig } from '@next/env';

const projectDir = process.cwd();

try {
  const { combinedEnv, loadedEnvFiles } = loadEnvConfig(projectDir);
  console.log('Environment configuration loaded successfully');
  console.log('Loaded env files:', loadedEnvFiles);
  
  // You can add more detailed logging here if needed
  // For example, logging specific environment variables (be careful not to log sensitive information)
  // console.log('API_URL:', combinedEnv.API_URL);

  export { combinedEnv, loadedEnvFiles };
} catch (error) {
  console.error('Failed to load environment configuration:', error);
  // You might want to throw the error here or handle it in some other way
  throw error;
}

This modification adds error handling and basic logging, which can help with debugging and provide more information about the environment configuration loading process.


LGTM! Consider exporting the loaded configuration.

The implementation looks correct. It imports the necessary function, gets the current working directory, and loads the environment configuration. However, you might want to consider exporting the result of loadEnvConfig for use in other parts of the application.

Consider modifying the code as follows:

 import { loadEnvConfig } from '@next/env';

 const projectDir = process.cwd();
-loadEnvConfig(projectDir);
+export const { combinedEnv, loadedEnvFiles } = loadEnvConfig(projectDir);

This change would allow other parts of your application to import and use the loaded environment configuration.

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.

Suggested change
import { loadEnvConfig } from '@next/env';
const projectDir = process.cwd();
loadEnvConfig(projectDir);
import { loadEnvConfig } from '@next/env';
const projectDir = process.cwd();
export const { combinedEnv, loadedEnvFiles } = loadEnvConfig(projectDir);

Comment on lines +11 to +29
class BaseApi {
constructor(protected readonly instance: AxiosInstance) {}

create({ url, data, params = {} }: IApiProps) {
return this.instance.post(url, data, params);
}

find({ url, params = {} }: Omit<IApiProps, 'data'>) {
return this.instance.get(url, { params });
}

update({ url, data, params = {} }: IApiProps) {
return this.instance.put(url, data, params);
}

delete({ url, params = {} }: Omit<IApiProps, 'data'>) {
return this.instance.delete(url, params);
}
}
Copy link

Choose a reason for hiding this comment

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

Consider adding error handling and request/response interceptors.

The BaseApi class provides a good abstraction for API operations. To enhance its robustness and functionality, consider the following suggestions:

  1. Implement error handling in each method to provide consistent error responses.
  2. Add request and response interceptors to the axios instance for tasks like adding authentication headers or handling common error scenarios.

Example of adding an interceptor:

instance.interceptors.response.use(
  (response) => response,
  (error) => {
    // Handle common errors (e.g., 401 Unauthorized)
    return Promise.reject(error);
  }
);

Comment on lines +31 to +45
export class ApiSHLink extends BaseApi {
constructor(protected readonly instance: AxiosInstance) {
super(instance);
}

async findLinks() {
return await this.find({
url: `/${EEndpoint.shareLinks}`,
});
}

async createLink(data: object) {
return await this.create({ url: `/${EEndpoint.shareLinks}`, data });
}
}
Copy link

Choose a reason for hiding this comment

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

Approve ApiSHLink implementation and suggest type improvement.

Great job implementing a service-specific class for share links. This addresses the previous suggestion and improves the overall structure of the API handling.

To further enhance type safety, consider defining a more specific type for the data parameter in the createLink method instead of using the generic object type. This will provide better documentation and catch potential errors at compile-time.

Example:

interface CreateLinkData {
  // Define the expected properties here
  url: string;
  // Add other relevant properties
}

async createLink(data: CreateLinkData) {
  // ...
}

src/app/utils/api.class.ts Outdated Show resolved Hide resolved
src/app/shared-links/Components/AddLinkDialog.tsx Outdated Show resolved Hide resolved
src/app/shared-links/Components/AddLinkDialog.tsx Outdated Show resolved Hide resolved
Comment on lines +77 to +131
return (
<Dialog open={!!open} fullWidth maxWidth="xs" onClose={() => onClose?.()}>
<StyledDialogTitle>Create a new Link</StyledDialogTitle>
<DialogContent style={{ padding: '5px 8px' }}>
<form onSubmit={handleSubmit(onSubmitForm)}>
<StyledDialogContent>
<TextField
label="User id"
error={!!errors.userId}
disabled
required
inputProps={{ readOnly: true }}
{...register('userId', {})}
/>
<TextField
label="Name"
error={!!errors.name}
required
helperText={errors.name ? errors.name.message : null}
placeholder="Name"
{...register('name', { required: 'Required field' })}
/>
<TextField
type="number"
label="PIN Code"
{...register('configPasscode', {
setValueAs: (value) => value || undefined,
})}
/>
<TextField
type="date"
label="Expiration Date"
InputLabelProps={{ shrink: true }}
{...register('configExp', {
setValueAs: (value) => value || undefined,
})}
/>
</StyledDialogContent>
</form>
</DialogContent>
<StyledDialogActions>
<Button color="inherit" variant="contained" onClick={onClose}>
Cancel
</Button>
<Button
type="submit"
color="success"
variant="contained"
onClick={handleSubmit(onSubmitForm)}
>
Create
</Button>
</StyledDialogActions>
</Dialog>
);
Copy link

Choose a reason for hiding this comment

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

Enhance accessibility for form inputs

The form inputs could benefit from improved accessibility attributes.

Consider adding aria-describedby attributes to connect error messages with their respective inputs:

<TextField
  label="Name"
  error={!!errors.name}
  required
  helperText={errors.name ? errors.name.message : null}
  placeholder="Name"
  aria-describedby={errors.name ? "name-error" : undefined}
  {...register('name', { required: 'Required field' })}
/>
{errors.name && <span id="name-error" style={{ display: 'none' }}>{errors.name.message}</span>}

Apply similar changes to other form inputs to improve screen reader support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: add a share link Show User Shared Links in Material-UI Tab Structure
5 participants