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

✨ Making the catalog for embedded in tegration connections #246

Merged
merged 7 commits into from
Feb 1, 2024

Conversation

naelob
Copy link
Contributor

@naelob naelob commented Jan 31, 2024

Summary by CodeRabbit

  • New Features

    • Introduced Tailwind CSS for styling and basic setup for a React component in the embedded catalog app.
    • Added functionality for managing linked users and OAuth authentication in the React app.
  • Refactor

    • Switched to @vitejs/plugin-react-swc for improved performance in the React app's build process.
  • Chores

    • Configured PostCSS with plugins for better CSS handling in the React project.

Copy link

render bot commented Jan 31, 2024

Copy link

changeset-bot bot commented Jan 31, 2024

⚠️ No Changeset found

Latest commit: 6dcaa8c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

coderabbitai bot commented Jan 31, 2024

Walkthrough

The project has undergone significant changes to enhance the React application's development and user interaction. It introduced Tailwind CSS for styling, optimized compilation with SWC, and added new components and hooks for managing providers and linked users. Additionally, it improved the API by adding a new method to retrieve linked users based on their origin ID.

Changes

File Path Change Summary
.../react/postcss.config.js Introduced PostCSS configuration with tailwindcss and autoprefixer.
.../react/src/App.tsx Defined a basic React component structure utilizing @tanstack/react-query.
.../react/src/index.css Added Tailwind CSS directives and set base font family and line height.
.../react/tailwind.config.js Configured Tailwind CSS with content paths, theme extensions, and plugins.
.../react/vite.config.ts Replaced @vitejs/plugin-react with @vitejs/plugin-react-swc for improved React compilation.
.../react/src/helpers/config.ts Introduced a configuration file exporting settings including API URL and ML frontend URL.
.../react/src/helpers/utils.ts Added functionality for managing provider configurations and retrieving provider information.
.../react/src/hooks/mutations/useLinkedUserMutation.tsx Introduced a custom hook for adding a linked user using @tanstack/react-query.
.../react/src/hooks/queries/useLinkedUserId.tsx Added a custom hook for fetching a linked user by their origin ID using @tanstack/react-query.
.../react/src/hooks/useOAuth.tsx Introduced a new React hook for OAuth authentication and modal window handling.
.../api/src/@core/linked-users/linked-users.controller.ts Added a method to retrieve a linked user by originId with API documentation.
.../api/src/@core/linked-users/linked-users.service.ts Added an asynchronous method to retrieve a linked user by originId using prisma.

Poem

🐇✨
In a burrow, deep and wide,
Changes bloom like spring outside.
Tailwind breezes, swift compile,
Dialog dances, all the while.
🌼🌿

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>.
    • Generate unit-tests for this file.
  • 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 tests 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 generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

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 as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • 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/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@ghost
Copy link

ghost commented Jan 31, 2024

👇 Click on the image for a new way to code review

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map legend

Copy link

socket-security bot commented Jan 31, 2024

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@vitejs/[email protected] filesystem, unsafe Transitive: environment, eval, network, shell +9 6.42 MB vitebot

🚮 Removed packages: npm/@vitejs/[email protected]

View full report↗︎

Copy link

socket-security bot commented Jan 31, 2024

🚨 Potential security issues detected. Learn more about Socket for GitHub ↗︎

To accept the risk, merge this PR and you will not be notified again.

Alert Package NoteSource
Install scripts npm/@swc/[email protected]
  • Install script: postinstall
  • Source: node postinstall.js

View full report↗︎

Next steps

What is an install script?

Install scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.

Packages should not be running non-essential scripts during install and there are often solutions to problems people solve with install scripts that can be run at publish time instead.

Take a deeper look at the dependency

Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev.

Remove the package

If you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency.

Mark a package as acceptable risk

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of ecosystem/package-name@version specifiers. e.g. @SocketSecurity ignore npm/[email protected] or ignore all packages with @SocketSecurity ignore-all

Copy link
Contributor

@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.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 3658fa2 and 9ebbba2.
Files ignored due to path filters (8)
  • apps/embedded-catalog/react/package.json is excluded by: !**/*.json
  • apps/embedded-catalog/react/public/vite.svg is excluded by: !**/*.svg
  • apps/embedded-catalog/react/src/assets/react.svg is excluded by: !**/*.svg
  • apps/embedded-catalog/react/tsconfig.json is excluded by: !**/*.json
  • apps/embedded-catalog/react/tsconfig.node.json is excluded by: !**/*.json
  • packages/api/swagger/swagger-spec.json is excluded by: !**/*.json
  • pnpm-lock.yaml is excluded by: !**/*.yaml
  • pnpm-workspace.yaml is excluded by: !**/*.yaml
Files selected for processing (6)
  • apps/embedded-catalog/react/postcss.config.js (1 hunks)
  • apps/embedded-catalog/react/src/App.tsx (1 hunks)
  • apps/embedded-catalog/react/src/index.css (1 hunks)
  • apps/embedded-catalog/react/tailwind.config.js (1 hunks)
  • apps/embedded-catalog/react/vite.config.ts (1 hunks)
  • apps/webapp/src/components/connections/ConnectionTable.tsx (1 hunks)
Files skipped from review due to trivial changes (2)
  • apps/embedded-catalog/react/postcss.config.js
  • apps/embedded-catalog/react/src/index.css
Additional comments: 4
apps/embedded-catalog/react/vite.config.ts (1)
  • 2-2: The switch to @vitejs/plugin-react-swc from @vitejs/plugin-react is correctly implemented. This change should enhance the build performance by utilizing SWC's faster compilation capabilities.
apps/embedded-catalog/react/tailwind.config.js (1)
  • 1-11: The Tailwind CSS configuration is correctly set up with appropriate content paths and an empty theme extension. This setup ensures that Tailwind can correctly purge unused styles in production and extend the theme as needed.
apps/embedded-catalog/react/src/App.tsx (1)
  • 1-17: The App component is correctly implemented with a basic structure and uses Tailwind CSS for styling. This serves as a good starting point for further UI development.
apps/webapp/src/components/connections/ConnectionTable.tsx (1)
  • 82-82: The modification to the dialog box opening condition in ConnectionTable.tsx is a logical improvement. It now considers the isGenerated state more effectively, enhancing the user experience by making the UI behavior more intuitive. However, ensure that the setIsGenerated function is correctly handling state changes to avoid potential issues with dialog state management.

Copy link

guardrails bot commented Jan 31, 2024

⚠️ We detected 2 security issues in this pull request:

Hard-Coded Secrets (2)
Severity Details Docs
Medium Title: Hex High Entropy String
clientId: 'fbb3125a89f366daf02c09f201522245c4453c1310f07ec2223c614fac130c78',
📚
Medium Title: Hex High Entropy String
clientId: '5f1d8d963c77285f339a',
📚

More info on how to fix Hard-Coded Secrets in General.


👉 Go to the dashboard for detailed results.

📥 Happy? Share your feedback with us.

Copy link
Contributor

@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.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9ebbba2 and 698594d.
Files ignored due to path filters (14)
  • apps/embedded-catalog/react/package.json is excluded by: !**/*.json
  • apps/embedded-catalog/react/public/assets/accounting/clearbooksLogo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/freeagent.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/freshbooks.jpeg is excluded by: !**/*.jpeg
  • apps/embedded-catalog/react/public/assets/accounting/pennylanelogo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/sageLogo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/crm/hubspot_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/crm/pipedrive_logo.jpeg is excluded by: !**/*.jpeg
  • apps/embedded-catalog/react/public/assets/crm/zendesk_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/crm/zoho_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/ticketing/front.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/tsconfig.json is excluded by: !**/*.json
  • apps/frontend-snippet/package.json is excluded by: !**/*.json
  • pnpm-lock.yaml is excluded by: !**/*.yaml
Files selected for processing (10)
  • apps/embedded-catalog/react/src/App.tsx (1 hunks)
  • apps/embedded-catalog/react/src/helpers/config.ts (1 hunks)
  • apps/embedded-catalog/react/src/helpers/utils.ts (1 hunks)
  • apps/embedded-catalog/react/src/hooks/mutations/useLinkedUserMutation.tsx (1 hunks)
  • apps/embedded-catalog/react/src/hooks/queries/useLinkedUserId.tsx (1 hunks)
  • apps/embedded-catalog/react/src/hooks/useOAuth.tsx (1 hunks)
  • apps/embedded-catalog/react/src/lib/index.tsx (1 hunks)
  • apps/embedded-catalog/react/vite.config.ts (1 hunks)
  • packages/api/src/@core/linked-users/linked-users.controller.ts (1 hunks)
  • packages/api/src/@core/linked-users/linked-users.service.ts (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • apps/embedded-catalog/react/vite.config.ts
Additional comments: 10
apps/embedded-catalog/react/src/helpers/config.ts (1)
  • 1-6: The configuration file correctly exports a config object containing environment variables for API URLs. Ensure that these environment variables are properly defined in the project's environment configuration files (e.g., .env files) to avoid runtime errors.
apps/embedded-catalog/react/src/App.tsx (1)
  • 1-21: The App component is correctly structured and uses QueryClientProvider from @tanstack/react-query to provide a React Query configuration context. Ensure that ProviderCard is imported correctly from ./lib and that it is the intended component to be rendered within this context.
apps/embedded-catalog/react/src/hooks/queries/useLinkedUserId.tsx (1)
  • 1-17: The useLinkedUser hook correctly uses useQuery from @tanstack/react-query to fetch linked user data. Ensure that the linked_users import from api is correctly set up and that the API URL constructed with config.API_URL is valid and accessible. Also, consider handling the JSON parsing with a try-catch block to gracefully handle any potential parsing errors.
apps/embedded-catalog/react/src/hooks/mutations/useLinkedUserMutation.tsx (1)
  • 1-40: The useLinkedUserMutation hook correctly uses useMutation from @tanstack/react-query for performing a POST request to add a linked user. Ensure that the API endpoint ${config.API_URL}/linked-users/create is correct and that the server is configured to accept and process the JSON payload. Additionally, consider adding error handling logic in the onError callback to provide more detailed feedback to the user or system.
packages/api/src/@core/linked-users/linked-users.service.ts (1)
  • 31-41: The getLinkedUserV2 method correctly uses Prisma to fetch a linked user based on originId. Ensure that the linked_user_origin_id field is correctly indexed in the database for optimal query performance. Also, the use of handleServiceError for error handling is appropriate, but ensure that it logs sufficient information for debugging purposes.
packages/api/src/@core/linked-users/linked-users.controller.ts (1)
  • 52-61: The getLinkedUserV2 method in LinkedUsersController is correctly implemented with appropriate API documentation using NestJS decorators. Ensure that the originId query parameter is validated to prevent potential injection attacks or errors. Additionally, consider adding more detailed response types in the @ApiResponse decorator for better API documentation.
apps/embedded-catalog/react/src/hooks/useOAuth.tsx (1)
  • 1-83: The useOAuth hook is well-structured for constructing OAuth URLs and handling the OAuth flow in a modal window. Ensure that the providersConfig and findProviderVertical functions are correctly implemented to support the OAuth configurations. Additionally, consider handling potential errors or edge cases, such as when authUrl is null or when the provider configuration is missing.
apps/embedded-catalog/react/src/lib/index.tsx (2)
  • 9-34: The LoadingOverlay component is correctly implemented to display a loading state with provider-specific information. Ensure that the provider object is always defined to avoid potential runtime errors when accessing properties like logoPath and name.
  • 47-120: The ProviderCard component is well-implemented, using custom hooks for mutation and query operations, and handling OAuth flow. Ensure that the mutate function from useLinkedUserMutation and the data from useLinkedUser are correctly handled, especially in cases where the mutation or query might fail. Additionally, consider adding error handling for these operations to improve user experience.
apps/embedded-catalog/react/src/helpers/utils.ts (1)
  • 1-146: The utility file correctly defines configurations for various OAuth providers and includes functions for accessing these configurations. Ensure that all client IDs and scopes are correctly configured and that any placeholders like in the freshsales configuration are replaced with actual values before deployment. Additionally, consider validating the vertical parameter in providersArray to ensure it matches one of the defined categories to prevent runtime errors.

Copy link
Contributor

@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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 698594d and e418a1a.
Files selected for processing (4)
  • apps/embedded-catalog/react/.env.example (1 hunks)
  • apps/embedded-catalog/react/src/helpers/utils.ts (1 hunks)
  • apps/embedded-catalog/react/src/index.css (1 hunks)
  • apps/embedded-catalog/react/src/lib/index.tsx (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • apps/embedded-catalog/react/src/helpers/utils.ts
  • apps/embedded-catalog/react/src/index.css
Additional comments: 3
apps/embedded-catalog/react/.env.example (1)
  • 1-1: The addition of VITE_BACKEND_DOMAIN in the .env.example file is a good practice, as it provides a clear example for developers on how to set up their local environment variables. However, ensure that this URL is intended only for development or example purposes and not used in production environments to avoid security risks.
apps/embedded-catalog/react/src/lib/index.tsx (2)
  • 1-6: The imports are well-organized and follow a consistent pattern, using alias paths for better readability and maintainability. This is a good practice as it makes the codebase easier to navigate.
  • 9-19: Defining interfaces RemoteUserInfo and ProviderCardProp enhances the type safety and readability of the component. This is a good practice in TypeScript development. Ensure that all properties are indeed required; otherwise, consider marking optional properties with ?.

Comment on lines 20 to 88
const ProviderCard = ({name, projectId, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")

const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);


let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
//create a new linkedUser based on the user data of the saas
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser!.id_linked_user
}

const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: config.ML_FRONTEND_URL, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});

const onWindowClose = () => {
}

useEffect(() => {
if (providerClicked && isReady) {
open(onWindowClose);
}
}, [providerClicked, isReady, open]);


const handleClick = () => {
setProviderClicked(true);
};

return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-zinc-900 hover:border-[0.1em] transition-colors duration-200"
>
<div className="text-center flex items-center">
<img src={`public/assets/crm/${name}_logo.png`} width={"35px"} className="pb-5 mr-3 rounded-sm"/>
<a href="#">
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>
</a>
</div>

<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
<a
href="#" className="inline-flex items-center text-indigo-600 hover:underline"
onClick={handleClick}
>
Integrate in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</a>
</div>
)
};
Copy link
Contributor

Choose a reason for hiding this comment

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

The ProviderCard component is well-structured, utilizing React hooks for state management and effects. However, there are a few areas for improvement:

  1. The mutate function is called directly within the component's render logic (lines 33-37). This side effect should be encapsulated within a useEffect hook or a callback function to avoid unintended mutations on each render.
  2. The linkedUserId is being set after a mutation call without checking if the mutation was successful (lines 38-40). Consider handling the mutation's success or failure states to ensure linkedUserId is set correctly.
  3. The TODO comment on line 45 suggests that the returnUrl is hardcoded. Ensure this is addressed before production deployment to avoid redirect issues.
  4. The onWindowClose function (lines 51-52) is empty. If it's intended to have logic, implement it; otherwise, remove it to clean up the code.

Consider refactoring to address these points for better maintainability and reliability.

-    mutate({ 
+    useEffect(() => {
+      if (!originId) {
+        mutate({ 
           linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem, 
           alias: linkedUserIdOrRemoteUserInfo.companyName,
           id_project: projectId
-    });
+        });
+      }
+    }, [linkedUserIdOrRemoteUserInfo, mutate, originId, projectId]);

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.

Suggested change
const ProviderCard = ({name, projectId, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")
const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);
let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
//create a new linkedUser based on the user data of the saas
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser!.id_linked_user
}
const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: config.ML_FRONTEND_URL, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});
const onWindowClose = () => {
}
useEffect(() => {
if (providerClicked && isReady) {
open(onWindowClose);
}
}, [providerClicked, isReady, open]);
const handleClick = () => {
setProviderClicked(true);
};
return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-zinc-900 hover:border-[0.1em] transition-colors duration-200"
>
<div className="text-center flex items-center">
<img src={`public/assets/crm/${name}_logo.png`} width={"35px"} className="pb-5 mr-3 rounded-sm"/>
<a href="#">
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>
</a>
</div>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
<a
href="#" className="inline-flex items-center text-indigo-600 hover:underline"
onClick={handleClick}
>
Integrate in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</a>
</div>
)
};
const ProviderCard = ({name, projectId, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")
const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);
let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
useEffect(() => {
if (!originId) {
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
}
}, [linkedUserIdOrRemoteUserInfo, mutate, originId, projectId]);
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser!.id_linked_user
}
const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: config.ML_FRONTEND_URL, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});
const onWindowClose = () => {
}
useEffect(() => {
if (providerClicked && isReady) {
open(onWindowClose);
}
}, [providerClicked, isReady, open]);
const handleClick = () => {
setProviderClicked(true);
};
return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-zinc-900 hover:border-[0.1em] transition-colors duration-200"
>
<div className="text-center flex items-center">
<img src={`public/assets/crm/${name}_logo.png`} width={"35px"} className="pb-5 mr-3 rounded-sm"/>
<a href="#">
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>
</a>
</div>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
<a
href="#" className="inline-flex items-center text-indigo-600 hover:underline"
onClick={handleClick}
>
Integrate in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</a>
</div>
)
};

Copy link
Contributor

@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.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between e418a1a and 90b28b2.
Files selected for processing (1)
  • apps/embedded-catalog/react/src/lib/index.tsx (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • apps/embedded-catalog/react/src/lib/index.tsx

Copy link

render bot commented Feb 1, 2024

Copy link
Contributor

@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.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 90b28b2 and 6dcaa8c.
Files ignored due to path filters (9)
  • apps/embedded-catalog/react/public/assets/accounting/clearbooks_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/freeagent_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/freshbooks_logo.jpeg is excluded by: !**/*.jpeg
  • apps/embedded-catalog/react/public/assets/accounting/pennylane_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/accounting/sage_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/crm/freshsales_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/crm/pipedrive_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/ticketing/front_logo.png is excluded by: !**/*.png
  • apps/embedded-catalog/react/public/assets/ticketing/zendesk_tcg_logo.png is excluded by: !**/*.png
Files selected for processing (5)
  • apps/embedded-catalog/react/index.ts (1 hunks)
  • apps/embedded-catalog/react/src/App.tsx (1 hunks)
  • apps/embedded-catalog/react/src/components/PanoraIntegrationCard.tsx (1 hunks)
  • apps/embedded-catalog/react/src/components/index.ts (1 hunks)
  • apps/embedded-catalog/react/src/helpers/utils.ts (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • apps/embedded-catalog/react/src/App.tsx
  • apps/embedded-catalog/react/src/helpers/utils.ts
Additional comments: 4
apps/embedded-catalog/react/src/components/index.ts (1)
  • 1-1: The export statement is correctly formatted and follows standard ES6 module syntax.
apps/embedded-catalog/react/index.ts (1)
  • 1-1: The export statement correctly re-exports the PanoraIntegrationCard from its location within the src/components directory, maintaining a clean entry point for the package.
apps/embedded-catalog/react/src/components/PanoraIntegrationCard.tsx (2)
  • 1-5: Imports are well-organized, separating external libraries from internal utilities and hooks. This enhances readability and maintainability.
  • 9-19: The component props are clearly defined with an interface, which is a good practice for type safety and readability in TypeScript.

Comment on lines +20 to +114
export const PanoraIntegrationCard = ({name, projectId, returnUrl, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")
const [loading, setLoading] = useState(false)

const vertical = findProviderVertical(name.toLowerCase())
console.log("vertical "+ vertical)
const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);


let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
//create a new linkedUser based on the user data of the saas
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser!.id_linked_user
}

const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: returnUrl, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});

const onWindowClose = () => {
setLoading(false);
return;
}

useEffect(() => {
if (loading && providerClicked && isReady) {
open(onWindowClose);
return;
}
}, [providerClicked, isReady, open, loading]);


const handleClick = () => {
setLoading(true);
setProviderClicked(true);
return;
};

return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-gray-200 transition-colors duration-200"
>
<div className=" flex items-center justify-center">
<img src={`public/assets/${vertical!.toLowerCase()}/${name}_logo.png`} width={"30px"} className="mx-3 mb-4 w-12 h-12 rounded-xl"/>
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>

</div>

<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
{!loading ?
<a
href="#" className="inline-flex items-center text-indigo-600 hover:underline"
onClick={handleClick}
>
Connect in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</a>

:
<>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">Continue in {name} </p>
<div className='flex justify-center items-center'>
<TailSpin
height="40"
width="70"
color="white"
ariaLabel="tail-spin-loading"
radius="1"
wrapperStyle={{}}
wrapperClass=""
visible={true}
/>
</div>
</>

}
</div>
)
Copy link
Contributor

Choose a reason for hiding this comment

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

The component function PanoraIntegrationCard is well-structured, utilizing React hooks for state management and effects. However, there are several areas for improvement:

  • The console log on line 26 should be removed for production code to avoid leaking potentially sensitive information.
  • The use of ! (non-null assertion operator) on line 43 is risky without checking if linkedUser is null or undefined. Consider adding a guard clause or default value.
  • The comment on line 48 about replacing the actual return URL should be addressed or tracked with a TODO if it's pending future changes.
  • The href="#" on line 86 should be replaced with a button element or preventDefault to avoid reloading the page on click.
- console.log("vertical "+ vertical)
+ // Consider removing console logs in production
- linkedUserId = linkedUser!.id_linked_user
+ linkedUserId = linkedUser ? linkedUser.id_linked_user : 'defaultId' // Example default value or handling
- href="#" className="inline-flex items-center text-indigo-600 hover:underline"
+ <button className="inline-flex items-center text-indigo-600 hover:underline" onClick={handleClick}>

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.

Suggested change
export const PanoraIntegrationCard = ({name, projectId, returnUrl, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")
const [loading, setLoading] = useState(false)
const vertical = findProviderVertical(name.toLowerCase())
console.log("vertical "+ vertical)
const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);
let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
//create a new linkedUser based on the user data of the saas
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser!.id_linked_user
}
const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: returnUrl, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});
const onWindowClose = () => {
setLoading(false);
return;
}
useEffect(() => {
if (loading && providerClicked && isReady) {
open(onWindowClose);
return;
}
}, [providerClicked, isReady, open, loading]);
const handleClick = () => {
setLoading(true);
setProviderClicked(true);
return;
};
return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-gray-200 transition-colors duration-200"
>
<div className=" flex items-center justify-center">
<img src={`public/assets/${vertical!.toLowerCase()}/${name}_logo.png`} width={"30px"} className="mx-3 mb-4 w-12 h-12 rounded-xl"/>
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>
</div>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
{!loading ?
<a
href="#" className="inline-flex items-center text-indigo-600 hover:underline"
onClick={handleClick}
>
Connect in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</a>
:
<>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">Continue in {name} </p>
<div className='flex justify-center items-center'>
<TailSpin
height="40"
width="70"
color="white"
ariaLabel="tail-spin-loading"
radius="1"
wrapperStyle={{}}
wrapperClass=""
visible={true}
/>
</div>
</>
}
</div>
)
export const PanoraIntegrationCard = ({name, projectId, returnUrl, linkedUserIdOrRemoteUserInfo}: ProviderCardProp) => {
const [providerClicked, setProviderClicked] = useState(false);
const [originId, setOriginId] = useState("")
const [loading, setLoading] = useState(false)
const vertical = findProviderVertical(name.toLowerCase())
// Consider removing console logs in production
const { mutate } = useLinkedUserMutation();
const {data: linkedUser} = useLinkedUser(originId);
let linkedUserId: string;
if (typeof linkedUserIdOrRemoteUserInfo === 'string') {
linkedUserId = linkedUserIdOrRemoteUserInfo;
} else {
//create a new linkedUser based on the user data of the saas
mutate({
linked_user_origin_id: linkedUserIdOrRemoteUserInfo.userIdInYourSystem,
alias: linkedUserIdOrRemoteUserInfo.companyName,
id_project: projectId
});
setOriginId(linkedUserIdOrRemoteUserInfo?.userIdInYourSystem)
//fetch the linkedId
linkedUserId = linkedUser ? linkedUser.id_linked_user : 'defaultId' // Example default value or handling
}
const { open, isReady } = useOAuth({
providerName: name.toLowerCase(),
returnUrl: returnUrl, // TODO: Replace with the actual return URL
projectId: projectId,
linkedUserId: linkedUserId,
onSuccess: () => console.log('OAuth successful'),
});
const onWindowClose = () => {
setLoading(false);
return;
}
useEffect(() => {
if (loading && providerClicked && isReady) {
open(onWindowClose);
return;
}
}, [providerClicked, isReady, open, loading]);
const handleClick = (e) => {
e.preventDefault();
setLoading(true);
setProviderClicked(true);
return;
};
return (
<div
className="max-w-sm p-6 bg-white border-[0.007em] border-gray-200 rounded-lg shadow dark:bg-zinc-800 hover:border-gray-200 transition-colors duration-200"
>
<div className=" flex items-center justify-center">
<img src={`public/assets/${vertical!.toLowerCase()}/${name}_logo.png`} width={"30px"} className="mx-3 mb-4 w-12 h-12 rounded-xl"/>
<h5 className="mb-2 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white">Integrate with {name}</h5>
</div>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">{getDescription(name.toLowerCase())}</p>
{!loading ?
<button className="inline-flex items-center text-indigo-600 hover:underline" onClick={handleClick}>
Connect in one click
<svg className="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
</svg>
</button>
:
<>
<p className="mb-3 font-normal text-gray-500 dark:text-gray-400">Continue in {name} </p>
<div className='flex justify-center items-center'>
<TailSpin
height="40"
width="70"
color="white"
ariaLabel="tail-spin-loading"
radius="1"
wrapperStyle={{}}
wrapperClass=""
visible={true}
/>
</div>
</>
}
</div>
)

@naelob naelob merged commit 05402d8 into main Feb 1, 2024
6 of 8 checks passed
@naelob naelob deleted the feat/catalog-embedded branch July 27, 2024 18:26
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.

1 participant