OfflineHQ / marketplace

https://offline.live/
GNU General Public License v3.0
0 stars 0 forks source link

300 unlock 6 shopify customer #301

Closed sebpalluel closed 7 months ago

sebpalluel commented 7 months ago

Type

enhancement


Description


Changes walkthrough

Relevant files
Tests
OffKeyAuth.stories.tsx
Add Storybook Stories for OffKeyAuth Component                     

libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.stories.tsx
  • Added new stories for OffKeyAuth component to demonstrate various
    states and interactions.
  • Utilized authMocks to simulate different authentication states and
    customer data.
  • +96/-120
    Enhancement
    OffKeyAuth.tsx
    Refactor OffKeyAuth Component for Enhanced State Management

    libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.tsx
  • Refactored to use ShopifyCustomerStatus for better state management.
  • Added handling for different customer statuses to render appropriate
    UI elements.
  • +181/-76
    OffKeyProfile.tsx
    Integrate useShopifyCustomer Hook in OffKeyProfile Component

    libs/features/unlock/shopify/src/lib/OffKeyProfile/OffKeyProfile.tsx
  • Integrated useShopifyCustomer hook to manage customer data and state.
  • Implemented dynamic rendering based on the customer's status.
  • +64/-51 
    useShopifyCustomer.tsx
    Implement useShopifyCustomer Hook for Customer Data Management

    libs/features/unlock/shopify/src/lib/hooks/useShopifyCustomer.tsx
  • Created a new hook useShopifyCustomer to fetch and manage customer
    data from Shopify.
  • Hook handles various states and provides customer data and status to
    components.
  • +73/-0   
    OffKeyHeaderConnected.tsx
    Enhance OffKeyHeaderConnected for Dynamic Text and Localization

    libs/features/unlock/shopify/src/lib/OffKeyHeaderConnected/OffKeyHeaderConnected.tsx
  • Enhanced to use interpolated strings for dynamic text based on
    customer data.
  • Added props for text customization and improved localization support.
  • +41/-9   

    PR-Agent usage: Comment /help on the PR to get a list of all available PR-Agent tools and their descriptions

    vercel[bot] commented 7 months ago

    The latest updates on your projects. Learn more about Vercel for Git ↗︎

    Name Status Preview Comments Updated (UTC)
    back-office ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 26, 2024 5:07pm
    marketplace ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 26, 2024 5:07pm
    unlock ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 26, 2024 5:07pm
    codiumai-pr-agent-free[bot] commented 7 months ago

    PR Description updated to latest commit (https://github.com/OfflineHQ/marketplace/commit/f630df84fdb68c9e250181cb13a04a42471580c1)

    codiumai-pr-agent-free[bot] commented 7 months ago

    PR Review

    ⏱️ Estimated effort to review [1-5] 5, because the PR introduces a significant amount of changes across multiple files and components, including new hooks, component modifications, and integration with external APIs. The complexity is high due to the need to understand the interactions between different parts of the system, such as authentication, customer status handling, and UI updates based on state changes.
    🧪 Relevant tests Yes
    🔍 Possible issues Possible Bug: The use of `toLowerCase()` directly on potentially undefined properties could lead to runtime errors. It's safer to ensure the property exists before calling `toLowerCase()`.
    Performance Concern: There are multiple places where the code could be optimized to avoid unnecessary re-renders or computations, especially in context providers and hooks.
    🔒 Security concerns No apparent security vulnerabilities were introduced in the changes. However, thorough testing and code review should be conducted to ensure that all user input is properly sanitized and that there are no potential data leaks.

    ✨ Review tool usage guide:
    **Overview:** The `review` tool scans the PR code changes, and generates a PR review which includes several types of feedbacks, such as possible PR issues, security threats and relevant test in the PR. More feedbacks can be [added](https://pr-agent-docs.codium.ai/tools/review/#general-configurations) by configuring the tool. The tool can be triggered [automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) every time a new PR is opened, or can be invoked manually by commenting on any PR. - When commenting, to edit [configurations](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L23) related to the review tool (`pr_reviewer` section), use the following template: ``` /review --pr_reviewer.some_config1=... --pr_reviewer.some_config2=... ``` - With a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/), use the following template: ``` [pr_reviewer] some_config1=... some_config2=... ``` See the review [usage page](https://pr-agent-docs.codium.ai/tools/review/) for a comprehensive guide on using this tool.
    codiumai-pr-agent-free[bot] commented 7 months ago

    PR Code Suggestions

    CategorySuggestions                                                                                                                                                       
    Enhancement
    Replace Promise.resolve() with simulated asynchronous operations in test mocks. ___ **The Promise.resolve() used in the connect and disconnect methods of walletAuthMocks should
    ideally be replaced with more realistic asynchronous operations that simulate actual
    network requests or interactions. This will provide a more accurate test environment and
    help catch issues related to asynchronous operations.** [libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.stories.tsx [22-23]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-d3cf1bf6ba1f6547521d8358ee0dbd3cbf52ec83cebf682e75620a1ded537602R22-R23) ```diff -connect: () => Promise.resolve(), -disconnect: () => Promise.resolve(), +connect: () => new Promise(resolve => setTimeout(resolve, 1000)), // Simulates network delay +disconnect: () => new Promise(resolve => setTimeout(resolve, 1000)), // Simulates network delay ```
    Enhance error handling in the mutation's onError callback. ___ **The error handling in the onError callback of connectWalletMutation only checks for a
    specific error message. It's recommended to handle different types of errors more robustly
    or log them appropriately for better debugging and user feedback.** [libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.tsx [82-84]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-dd427743a002e3dad8c75f54ed95a9092983490a56a5fc378a0e3ec2a5d6bdf6R82-R84) ```diff if (error.message.includes('Wallet address does not match')) { setAccountNotMatching(true); +} else { + console.error('Unhandled error:', error); } ```
    Add default text for missing customer or offKeyState to prevent UI issues. ___ **To ensure that the component handles the absence of customer or offKeyState gracefully,
    consider adding a fallback or default text when these values are not available. This can
    prevent potential runtime errors or display issues in the UI.** [libs/features/unlock/shopify/src/lib/OffKeyGate/OffKeyGate.tsx [99-104]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-b04caa7332ebff9c207f545552e87b6297915d203992f9e5bfe4f6569ecd2ed8R99-R104) ```diff {offKeyState && customer ? (
    - {textsSubtitle[offKeyState]} - {textsMainText[offKeyState]} + {textsSubtitle[offKeyState] || 'Default subtitle'} + {textsMainText[offKeyState] || 'Default main text'} ... ```
    Best practice
    Use a function to dynamically generate wallet addresses for testing. ___ **The walletInStorage array includes hardcoded addresses which might not reflect dynamic
    testing scenarios. Consider using a function or a factory to generate these addresses
    dynamically based on the test requirements.** [libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.stories.tsx [45]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-d3cf1bf6ba1f6547521d8358ee0dbd3cbf52ec83cebf682e75620a1ded537602R45-R45) ```diff -walletInStorage: [{ address }, { address: '0x214123135' }], +walletInStorage: generateWalletAddresses(), ```
    Replace direct console logging with a conditional check for environment or a dedicated error handling mechanism. ___ **Replace the console.log with a more robust error handling mechanism. Logging to the
    console is not suitable for production environments as it can expose sensitive information
    and does not provide a way to centrally manage errors. Consider using a dedicated error
    reporting service or at least wrapping the logging in a development mode check.** [libs/features/unlock/shopify/src/lib/OffKeyProfile/OffKeyProfile.tsx [85]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-4b035f23e367c8645366640c5b6355e6bdd60a52f6a10b88ef9f4f93db8a16ebR85-R85) ```diff -console.log('error connecting to dapp', error); +if (process.env.NODE_ENV === 'development') { + console.error('Error connecting to dapp:', error); +} else { + // Send error to monitoring service + monitoringService.reportError(error); +} ```
    Use specific error handling in catch blocks to improve error management. ___ **Use a more specific error type in the catch block to handle different types of errors
    appropriately. Using a generic error catch can make debugging harder and might not provide
    the necessary information or actions based on the type of error.** [libs/features/unlock/shopify/src/lib/OffKeyProfile/OffKeyProfile.tsx [150-152]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-4b035f23e367c8645366640c5b6355e6bdd60a52f6a10b88ef9f4f93db8a16ebR150-R152) ```diff } catch (e) { - console.error('Error signing out', e); + if (e instanceof NetworkError) { + console.error('Network error during sign out:', e); + } else { + console.error('Unexpected error during sign out:', e); + } throw e; } ```
    Link TODO comments to an issue tracker for better tracking and clarity. ___ **Avoid using inline comments for TODOs without a clear action plan or ticket reference.
    This can lead to forgotten or unclear intentions in the codebase. Instead, link TODOs to
    an issue tracker or provide more detailed comments.** [libs/features/unlock/shopify/src/lib/OffKeyProfile/OffKeyProfile.tsx [87]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-4b035f23e367c8645366640c5b6355e6bdd60a52f6a10b88ef9f4f93db8a16ebR87-R87) ```diff -//TODO: Handle connection error display +// TODO: Implement user-friendly error display for connection issues. See issue #1234 in the issue tracker for more details. ```
    Use TypeScript enums for OffKeyState to enhance type safety and readability. ___ **To enhance the type safety and readability of the code, consider using TypeScript enums
    for the OffKeyState values instead of accessing them directly as string indexes. This
    approach can help prevent typos and logical errors.** [libs/features/unlock/shopify/src/lib/OffKeyGate/OffKeyGate.tsx [47]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-b04caa7332ebff9c207f545552e87b6297915d203992f9e5bfe4f6569ecd2ed8R47-R47) ```diff +enum OffKeyState { + Unlocked = 'Unlocked', + Unlocking = 'Unlocking', + Used = 'Used', + Locked = 'Locked' +} + [OffKeyState.Unlocked]: interpolateString( textGate.subtitle[OffKeyState.Unlocked], locale, customer, ), ```
    Add optional chaining to handle potential null or undefined responses safely. ___ **Consider handling the case where mintLoyaltyCardWithPassword might throw an exception or
    return a null/undefined response before accessing the status property.** [libs/integrations/external-api-handlers/src/lib/shopify/index.spec.ts [222-223]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-df93842e018141cf209891b7f7fa3c10fbc063d5eed17ace2701d2d12a234844R222-R223) ```diff const response = await shopifyHandler.mintLoyaltyCardWithPassword(options); -expect(response.status).toBe(401); +expect(response?.status).toBe(401); ```
    Use descriptive naming for mock data to enhance the readability and maintainability of tests. ___ **To improve test clarity and maintainability, use descriptive names for mock values and
    constants, particularly for addresses and other identifiers.** [libs/integrations/external-api-handlers/src/lib/shopify/index.spec.ts [561-565]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-df93842e018141cf209891b7f7fa3c10fbc063d5eed17ace2701d2d12a234844R561-R565) ```diff -address: 'test-address', -shop: 'example.myshopify.com', +address: 'mockTestAddress', +shop: 'mockExampleShop.myshopify.com', timestamp: Date.now().toString(), -signature: 'validSignature', +signature: 'mockValidSignature', ```
    Maintainability
    Ensure relevant parameters are passed to the connect function. ___ **The mutation function connect is being called with parameters that might not always be
    necessary. Refactor the code to ensure that only relevant parameters are passed based on
    the user's action.** [libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.tsx [128]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-dd427743a002e3dad8c75f54ed95a9092983490a56a5fc378a0e3ec2a5d6bdf6R128-R128) ```diff -connectWalletMutation.mutateAsync({ isCreatingAccount: true }) +connectWalletMutation.mutateAsync({ walletAddress, isCreatingAccount: true }) ```
    Refactor repeated string interpolation into a utility function. ___ **The interpolation of strings for UI text elements is done multiple times with similar
    parameters. Consider creating a utility function to handle this, reducing redundancy and
    improving maintainability.** [libs/features/unlock/shopify/src/lib/OffKeyAuth/OffKeyAuth.tsx [91-99]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-dd427743a002e3dad8c75f54ed95a9092983490a56a5fc378a0e3ec2a5d6bdf6R91-R99) ```diff -createNewAccount: interpolateString(textAuth.createNewAccount, locale, customer), -useExistingAccount: interpolateString(textAuth.useExistingAccount, locale, customer), +function getLocalizedText(key) { + return interpolateString(textAuth[key], locale, customer); +} +createNewAccount: getLocalizedText('createNewAccount'), +useExistingAccount: getLocalizedText('useExistingAccount'), ```
    Refactor the sign-out function to improve code maintainability and separation of concerns. ___ **Refactor the signOutUserAction function to separate concerns for better maintainability
    and testing. Currently, the function handles UI routing, state management, and business
    logic, which can be split into smaller, more manageable functions.** [libs/features/unlock/shopify/src/lib/OffKeyProfile/OffKeyProfile.tsx [136-157]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-4b035f23e367c8645366640c5b6355e6bdd60a52f6a10b88ef9f4f93db8a16ebR136-R157) ```diff -const signOutUserAction = useCallback( - async (error?: boolean) => { - try { - setUserActionLoading(true); - disconnectFromDapp(user.address); - await disconnect(); - let newPathname = pathname.split('/0x')[0]; - if (searchParams?.toString()) { - const params = new URLSearchParams(searchParams.toString()); - newPathname += `?${params.toString()}`; - } - await router.replace(newPathname); - } catch (e) { - console.error('Error signing out', e); - throw e; - } finally { - setUserActionLoading(false); - } - }, - [disconnect], -); +const handleSignOut = useCallback(async () => { + try { + setUserActionLoading(true); + await performSignOut(); + } catch (e) { + console.error('Error during sign out:', e); + throw e; + } finally { + setUserActionLoading(false); + } +}, [performSignOut]); +const performSignOut = useCallback(async () => { + disconnectFromDapp(user.address); + await disconnect(); + await updateRouteAfterSignOut(); +}, [disconnect, user.address, updateRouteAfterSignOut]); + +const updateRouteAfterSignOut = useCallback(() => { + let newPathname = pathname.split('/0x')[0]; + if (searchParams?.toString()) { + const params = new URLSearchParams(searchParams.toString()); + newPathname += `?${params.toString()}`; + } + router.replace(newPathname); +}, [pathname, searchParams, router]); + ```
    Refactor repetitive text assignments into a helper function for better maintainability. ___ **Consider using a more concise and maintainable approach to handle the state-dependent text
    assignments by creating a helper function. This function can take the textGate object,
    locale, and customer as parameters and return the appropriate text based on the
    offKeyState. This will reduce redundancy and improve code readability.** [libs/features/unlock/shopify/src/lib/OffKeyGate/OffKeyGate.tsx [46-88]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-b04caa7332ebff9c207f545552e87b6297915d203992f9e5bfe4f6569ecd2ed8R46-R88) ```diff -const textsSubtitle = { +const getTexts = (textType) => ({ [OffKeyState.Unlocked]: interpolateString( - textGate.subtitle[OffKeyState.Unlocked], + textGate[textType][OffKeyState.Unlocked], locale, customer, ), [OffKeyState.Unlocking]: interpolateString( - textGate.subtitle[OffKeyState.Unlocking], + textGate[textType][OffKeyState.Unlocking], locale, customer, ), ... -}; +}); +const textsSubtitle = getTexts('subtitle'); +const textsMainText = getTexts('mainText'); + ```
    Extract repeated setup code into a separate function to reduce code duplication. ___ **Refactor the repeated setup code for ShopifyWebhookAndApiHandler and mockRequest into a
    separate function to avoid duplication and improve maintainability.** [libs/integrations/external-api-handlers/src/lib/shopify/index.spec.ts [557-566]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-df93842e018141cf209891b7f7fa3c10fbc063d5eed17ace2701d2d12a234844R557-R566) ```diff -beforeEach(() => { - handler = new ShopifyWebhookAndApiHandler(); - mockRequest = createMockRequest( +function setupHandlerAndRequest() { + const handler = new ShopifyWebhookAndApiHandler(); + const mockRequest = createMockRequest( new URLSearchParams({ address: 'test-address', shop: 'example.myshopify.com', timestamp: Date.now().toString(), signature: 'validSignature', }), ); + return { handler, mockRequest }; +} + +beforeEach(() => { + const { handler, mockRequest } = setupHandlerAndRequest(); }); ```
    Bug
    Normalize address comparisons to prevent case sensitivity issues. ___ **Ensure consistent use of string case comparison for addresses. The current implementation
    uses toLowerCase() inconsistently, which could lead to logical errors or security issues
    if addresses are compared in a case-sensitive manner elsewhere in the code.** [libs/integrations/external-api-handlers/src/lib/shopify/index.ts [201-205]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-f01dee98100c01117884ab045ae1560ae9e326c3ecf55b3ac4e2f15531a2ef4cR201-R205) ```diff -if (shopifyCustomer && shopifyCustomer.address.toLowerCase() !== ownerAddress.toLowerCase()) { +const normalizedCustomerAddress = shopifyCustomer.address.toLowerCase(); +const normalizedOwnerAddress = ownerAddress.toLowerCase(); +if (shopifyCustomer && normalizedCustomerAddress !== normalizedOwnerAddress) { throw new ForbiddenError('Invalid owner address. The owner address must match the address of the customer.'); } ```
    Security
    Sanitize the className prop to prevent potential security risks. ___ **Instead of directly using the className prop in the JSX, it's a good practice to sanitize
    or validate this prop to avoid potential security risks such as Cross-Site Scripting (XSS)
    if the class names are dynamically generated or user-provided.** [libs/features/unlock/shopify/src/lib/OffKeyGate/OffKeyGate.tsx [100]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-b04caa7332ebff9c207f545552e87b6297915d203992f9e5bfe4f6569ecd2ed8R100-R100) ```diff -
    +
    ```
    Validate address and shop parameters to prevent processing invalid requests. ___ **Add validation to check if the address and shop parameters are well-formed before
    proceeding with the request handling in createShopifyCustomer.** [libs/integrations/external-api-handlers/src/lib/shopify/index.spec.ts [559-565]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-df93842e018141cf209891b7f7fa3c10fbc063d5eed17ace2701d2d12a234844R559-R565) ```diff mockRequest = createMockRequest( new URLSearchParams({ address: 'test-address', shop: 'example.myshopify.com', timestamp: Date.now().toString(), signature: 'validSignature', }), ); +if (!isValidAddress(mockRequest.address) || !isValidShop(mockRequest.shop)) { + throw new BadRequestError('Invalid address or shop'); +} ```
    Performance
    Memoize text objects to improve component performance. ___ **To improve the performance of the component, consider memoizing the computed text objects
    (textsSubtitle, textsMainText, textsKeyStatus) using useMemo hook. This prevents
    unnecessary recalculations when the component re-renders without changes to its
    dependencies.** [libs/features/unlock/shopify/src/lib/OffKeyGate/OffKeyGate.tsx [46-66]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-b04caa7332ebff9c207f545552e87b6297915d203992f9e5bfe4f6569ecd2ed8R46-R66) ```diff -const textsSubtitle = { +const textsSubtitle = useMemo(() => ({ [OffKeyState.Unlocked]: interpolateString( textGate.subtitle[OffKeyState.Unlocked], locale, customer, ), ... -}; +}), [textGate, locale, customer]); ```
    Robustness
    Add error handling for the InsertShopifyCustomer method to ensure robustness. ___ **Ensure that the InsertShopifyCustomer method handles exceptions properly, especially when
    the database operation fails.** [libs/integrations/external-api-handlers/src/lib/shopify/index.spec.ts [587-592]](https://github.com/OfflineHQ/marketplace/pull/301/files#diff-df93842e018141cf209891b7f7fa3c10fbc063d5eed17ace2701d2d12a234844R587-R592) ```diff -expect(adminSdk.InsertShopifyCustomer).toHaveBeenCalledWith({ - object: { - organizerId: 'test-organizer-id', - id: 'test-customer-id', - address: 'test-address', - }, -}); +try { + await adminSdk.InsertShopifyCustomer({ + object: { + organizerId: 'test-organizer-id', + id: 'test-customer-id', + address: 'test-address', + }, + }); + expect(true).toBe(true); // Expect the operation to succeed without throwing +} catch (error) { + expect(true).toBe(false); // Fail the test if an error is thrown +} ```

    ✨ Improve tool usage guide:
    **Overview:** The `improve` tool scans the PR code changes, and automatically generates suggestions for improving the PR code. The tool can be triggered [automatically](https://pr-agent-docs.codium.ai/usage-guide/automations_and_usage/#github-app-automatic-tools-when-a-new-pr-is-opened) every time a new PR is opened, or can be invoked manually by commenting on a PR. - When commenting, to edit [configurations](https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml#L78) related to the improve tool (`pr_code_suggestions` section), use the following template: ``` /improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=... ``` - With a [configuration file](https://pr-agent-docs.codium.ai/usage-guide/configuration_options/), use the following template: ``` [pr_code_suggestions] some_config1=... some_config2=... ``` See the improve [usage page](https://pr-agent-docs.codium.ai/tools/improve/) for a comprehensive guide on using this tool.