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

feat: create report modal (BAL-3607) #3052

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open

feat: create report modal (BAL-3607) #3052

wants to merge 6 commits into from

Conversation

r4zendev
Copy link
Collaborator

@r4zendev r4zendev commented Feb 13, 2025

Changes

  • Introduces popup for creating reports
  • Adjusts customer config that is being sent to the client to include demo customer data.
  • Small refactoring initiatives, such as creating merchant monitoring module to share the client for customer module and allow gathering data required for demo accounts in one request (customers/by-currect-project-id).

Examples

image image image image

Summary by CodeRabbit

  • New Features

    • Introduced a business report card that clearly indicates remaining reports, demo days, and account status.
    • Launched an interactive report creation dialog with form validations, loading indicators, and success feedback.
    • Enhanced the monitoring page with an intuitive button for initiating report submissions.
    • Added demo access details to enhance customer information visibility.
  • Refactor

    • Updated component rendering conditions to leverage refined demo access details.
    • Reorganized dependencies and modules to streamline Merchant Monitoring functionality.
    • Improved error handling and response structure in customer-related methods.

@r4zendev r4zendev self-assigned this Feb 13, 2025
Copy link

changeset-bot bot commented Feb 13, 2025

⚠️ No Changeset found

Latest commit: 7736dc5

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.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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 Feb 13, 2025

Walkthrough

This pull request introduces a series of changes across both the front-end and back-end. Updates include modifications of customer configuration properties used for conditional rendering, new components and hooks for business and merchant reporting functions, and extensive refactoring of import paths for the MerchantMonitoringClient. Additionally, enhancements have been made to debugging aids and schema validations, and a new MerchantMonitoringModule has been integrated into the application's module system.

Changes

File(s) Change Summary
apps/backoffice-v2/src/common/components/molecules/GetFullAccessCard/GetFullAccessCard.tsx
services/workflows-service/src/customer/fetchers.ts
services/workflows-service/src/customer/schemas/zod-schemas.ts
services/workflows-service/src/customer/customer.controller.external.ts
services/workflows-service/src/customer/customer.service.ts
apps/backoffice-v2/src/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic.tsx
Updated customer configuration handling: the logic now accesses demoAccessDetails.showFullAccessPopup instead of a flat property, with associated schema and service changes to support nested demo access details.
apps/backoffice-v2/src/domains/business-reports/components/BusinessReportsLeftCard/BusinessReportsLeftCard.tsx
apps/backoffice-v2/src/domains/business-reports/hooks/mutations/useCreateBusinessReportMutation/useCreateBusinessReportMutation.tsx
apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx
apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx
apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx
apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts
Added new components and hooks to support business/merchant reporting. This includes a new left card for report status, a dialog for report creation with form handling, and updates to the mutation hook to support options like disableToast.
Multiple files in services/workflows-service/src/... (e.g., alert.service.intg.test.ts, business-report.*, collection-flow.*, end-user.*, workflow.*, etc.)
services/workflows-service/src/app.module.ts
services/workflows-service/src/customer/customer.module.ts
services/workflows-service/src/common/guards/token-guard/token-auth.module.ts
services/workflows-service/src/merchant-monitoring/merchant-monitoring.module.ts
Refactored import paths for the MerchantMonitoringClient, moving it from the business-report directory to a dedicated merchant-monitoring folder. A new MerchantMonitoringModule was added and integrated into various modules to support dependency injection and lifecycle management.
apps/backoffice-v2/src/common/components/organisms/Dialog/Dialog.Content.tsx Added a new line to set the displayName property for the DialogContent component, improving its visibility in debugging tools.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant P as MerchantMonitoringPage
  participant D as CreateMerchantReportDialog
  participant H as useCreateMerchantReportDialogLogic
  participant M as useCreateBusinessReportMutation

  U->>P: Click "Create Report" Button
  P->>D: Open Dialog
  D->>H: Initialize form state and metrics
  U->>D: Fill and submit form
  D->>H: Handle form submission
  H->>M: Trigger report creation mutation
  M-->>H: Return success or error
  H-->>D: Update state (show success/error)
  D-->>U: Display corresponding message
Loading

Possibly related PRs

Poem

I'm a rabbit with hops so bright,
Leaping through code both day and night,
New dialogs and schemas, oh what a sight!
Modules and hooks in a neat parade, 🐰
Celebrating changes that we lovingly made.

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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
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.

Actionable comments posted: 5

🔭 Outside diff range comments (1)
services/workflows-service/src/global.d.ts (1)

15-35: 🛠️ Refactor suggestion

Reduce usage of any type.

The extensive use of any type in these declarations bypasses TypeScript's type checking, which could lead to runtime errors.

Consider:

  1. Using more specific types instead of any
  2. If the type is truly unknown, use unknown as it's safer than any
  3. If the type is complex, consider creating a proper type definition

Example for the WorkflowRuntimeData type:

export type WorkflowRuntimeData = Omit<_WorkflowRuntimeData, 'context'> & {
-  context: any;
+  context: unknown;
-  config: WorkflowConfig | any;
+  config: WorkflowConfig | Record<string, unknown>;
};
🧹 Nitpick comments (15)
services/workflows-service/src/customer/customer.controller.external.ts (1)

84-86: Use NotFoundException instead of BadRequestException for absent resources.
Throwing BadRequestException implies invalid request data, whereas an absent resource typically merits NotFoundException for clarity and proper HTTP status semantics.

-      throw new BadRequestException('Customer not found');
+      throw new NotFoundException('Customer not found');
services/workflows-service/src/customer/customer.module.ts (1)

1-1: Verify necessity of forwardRef; otherwise, remove it.
The module imports forwardRef alongside MerchantMonitoringModule, but forwardRef does not appear to be used. If there is no cyclical dependency, you can safely remove it. In all other respects, adding MerchantMonitoringModule to imports is well-aligned with your modular approach.

-import { forwardRef, Module } from '@nestjs/common';
+import { Module } from '@nestjs/common';

Also applies to: 10-10, 13-13

apps/backoffice-v2/src/domains/business-reports/components/BusinessReportsLeftCard/BusinessReportsLeftCard.tsx (3)

5-9: Enhance props validation.

Consider adding validation for the numeric values:

export type BusinessReportsLeftCardProps = {
-  reportsLeft: number | null | undefined;
+  reportsLeft: number | null | undefined;
+  /** @invariant When defined, must be >= 0 */
-  demoDaysLeft: number | null | undefined;
+  demoDaysLeft: number | null | undefined;
+  /** @invariant When defined, must be >= 0 */
  className?: string;
};

25-25: Extract state determination logic.

The state determination logic could be moved to a separate function for better maintainability.

+const getCardState = (demoDaysLeft: number, reportsLeft: number) => {
+  if (demoDaysLeft <= 0) return 'expired';
+  if (reportsLeft <= 0) return 'noReports';
+  return 'active';
+};

-const state = demoDaysLeft <= 0 ? 'expired' : reportsLeft <= 0 ? 'noReports' : 'active';
+const state = getCardState(demoDaysLeft, reportsLeft);

27-36: Consider externalizing messages.

Moving messages to a separate constant would improve maintainability and make it easier to add translations later.

+const CARD_MESSAGES: Record<string, (props: { reportsLeft: number; demoDaysLeft: number }) => ReactNode> = {
+  expired: () => <span className="text-destructive">Your demo account has expired!</span>,
+  noReports: () => <span className="text-destructive">You don&apos;t have any reports left!</span>,
+  active: ({ reportsLeft, demoDaysLeft }) => (
+    <span>
+      You have <span className="font-bold">{reportsLeft} free reports</span> left to create,
+      available for <span className="font-bold">{demoDaysLeft} days.</span>
+    </span>
+  ),
+};

-const messages: Record<string, ReactNode> = {
-  expired: <span className="text-destructive">Your demo account has expired!</span>,
-  noReports: <span className="text-destructive">You don&apos;t have any reports left!</span>,
-  active: (
-    <span>
-      You have <span className="font-bold">{reportsLeft} free reports</span> left to create,
-      available for <span className="font-bold">{demoDaysLeft} days.</span>
-    </span>
-  ),
-};
services/workflows-service/src/business-report/business-report.module.ts (1)

7-15: Address circular dependencies in the module system.

The presence of multiple circular dependencies (marked with eslint-disable comments) suggests a need for architectural refactoring.

Consider:

  1. Extracting shared functionality into a separate module
  2. Using event-based communication between modules
  3. Implementing the mediator pattern to decouple modules
  4. Creating interfaces to break circular dependencies
apps/backoffice-v2/src/domains/business-reports/hooks/mutations/useCreateBusinessReportMutation/useCreateBusinessReportMutation.tsx (2)

9-14: Consider adding JSDoc documentation for the options parameter.

The function accepts an options object with multiple properties but lacks documentation explaining their purpose.

Add JSDoc:

+/**
+ * Hook for creating business reports with customizable success handling and toast notifications.
+ * @param options - Configuration options
+ * @param options.onSuccess - Callback function called after successful mutation
+ * @param options.disableToast - Flag to disable success toast notification
+ */
 export const useCreateBusinessReportMutation = (options?: {
   onSuccess?: <TData>(data: TData) => void;
   disableToast?: boolean;
 }) => {

43-54: Consider adding a loading toast for better UX.

The mutation shows success/error toasts but doesn't indicate when it's in progress.

Add loading state notification:

   onSuccess: data => {
     if (customer?.config?.isExample) {
       return;
     }

     void queryClient.invalidateQueries();

     if (!disableToast) {
+      toast.dismiss('creating-report');
       toast.success(t(`toast:business_report_creation.success`));
     }

     onSuccess?.(data);
   },
+  onMutate: () => {
+    if (!disableToast) {
+      toast.loading('Creating report...', { id: 'creating-report' });
+    }
+  },
apps/backoffice-v2/src/common/components/molecules/GetFullAccessCard/GetFullAccessCard.tsx (1)

15-21: Consider adding loading state UI.

The component returns null during loading, which might cause layout shifts. Consider showing a skeleton or placeholder during loading.

Add loading state:

   if (
     env.VITE_ENVIRONMENT_NAME === 'production' ||
-    isLoading ||
     !customer?.config?.demoAccessDetails?.showFullAccessPopup
   ) {
     return null;
   }

+  if (isLoading) {
+    return <div className="fixed bottom-8 right-8 h-[200px] w-[448px] animate-pulse rounded-md bg-gray-200" />;
+  }
services/workflows-service/src/customer/customer.service.ts (2)

24-42: Consider making demo access configuration values configurable.

The method contains hardcoded values that should be configurable:

  • Default max business reports (10)
  • Demo expiration period (14 days)

Consider moving these values to environment variables or configuration:

+import { env } from '@/env';
+
 async getDemoAccessDetails(customer: TCustomerWithFeatures): Promise<TDemoAccessDetails | null> {
   const { id: customerId, config, createdAt } = customer;

   if (!config || !config.isDemoAccount || !createdAt) {
     return null;
   }

   const businessReportsCount = await this.merchantMonitoringClient.count({
     customerId,
   });

   return {
     totalReports: businessReportsCount,
-    maxBusinessReports: config.maxBusinessReports ?? 10,
+    maxBusinessReports: config.maxBusinessReports ?? env.DEFAULT_MAX_BUSINESS_REPORTS ?? 10,
     showFullAccessPopup: config.showFullAccessPopup ?? false,
     // FIXME: should count from the first login date / should be passed on creation ?
-    expiresAt: dayjs(createdAt).add(14, 'days').unix(),
+    expiresAt: dayjs(createdAt).add(env.DEMO_EXPIRATION_DAYS ?? 14, 'days').unix(),
   };
 }

39-40: Address the FIXME comment regarding expiration date calculation.

The comment indicates uncertainty about when to start counting the expiration period.

Would you like me to:

  1. Generate a solution that tracks the first login date?
  2. Open an issue to track this requirement?
apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1)

133-134: Consider using a more robust URL validation approach.

The current regex might miss some edge cases in URL validation.

Consider using a dedicated URL validation library or the built-in URL constructor:

-const URL_REGEX = /((https?):\/\/)?([a-zA-Z0-9-_]+\.)+[a-zA-Z0-9]+(\.[a-z]{2})?(\/[a-zA-Z0-9_#-]+)*(\/)?(\?[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+(&[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*)?(#[a-zA-Z0-9_-]+)?/;
+const isValidUrl = (url: string) => {
+  try {
+    new URL(url.startsWith('http') ? url : `https://${url}`);
+    return true;
+  } catch {
+    return false;
+  }
+};

Then update the schema:

 export const CreateBusinessReportDialogSchema = z.object({
-  websiteUrl: z.string().regex(URL_REGEX, {
-    message: 'Invalid website URL',
-  }),
+  websiteUrl: z.string().refine(isValidUrl, {
+    message: 'Invalid website URL',
+  }),
   // ...rest of the schema
 });
apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx (2)

81-82: Consider adding a comment explaining the disable condition.

The disable condition combines two checks but lacks documentation explaining the business logic behind it.

+  // Disable form when either reports quota is exhausted or demo period has ended
   const shouldDisableForm =
     (reportsLeft && reportsLeft <= 0) || (demoDaysLeft && demoDaysLeft <= 0);

62-65: Consider making the completion time configurable.

The "24 hours" completion time is hardcoded. Consider making it configurable through props or environment variables for flexibility.

+  type CreateMerchantReportDialogProps = {
+    children: React.ReactNode;
+    estimatedCompletionHours?: number;
+  };

   // In the success content
-  <p className="font-semibold">Ready in up to 24 hours</p>
+  <p className="font-semibold">Ready in up to {estimatedCompletionHours ?? 24} hours</p>
apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx (1)

103-121: Refactor duplicate button code.

The button code is duplicated between the enabled and disabled states. Consider extracting it to a reusable component.

+ const CreateReportButton = ({ disabled }: { disabled: boolean }) => (
+   <Button
+     className={`flex items-center gap-2 bg-purple-600 font-semibold text-white hover:bg-purple-500 aria-disabled:pointer-events-none aria-disabled:opacity-50`}
+     aria-disabled={disabled}
+   >
+     <Plus />
+     <span>Create a report</span>
+   </Button>
+ );

  {createBusinessReport?.enabled ? (
    <CreateMerchantReportDialog>
-     <Button
-       className={`flex items-center gap-2 bg-purple-600 font-semibold text-white hover:bg-purple-500 aria-disabled:pointer-events-none aria-disabled:opacity-50`}
-       aria-disabled={!createBusinessReport?.enabled}
-     >
-       <Plus />
-       <span>Create a report</span>
-     </Button>
+     <CreateReportButton disabled={!createBusinessReport?.enabled} />
    </CreateMerchantReportDialog>
  ) : (
-   <Button
-     className={`flex items-center gap-2 bg-purple-600 font-semibold text-white hover:bg-purple-500 aria-disabled:pointer-events-none aria-disabled:opacity-50`}
-     aria-disabled={!createBusinessReport?.enabled}
-   >
-     <Plus />
-     <span>Create a report</span>
-   </Button>
+   <CreateReportButton disabled={!createBusinessReport?.enabled} />
  )}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 686df12 and 7cf4fca.

📒 Files selected for processing (30)
  • apps/backoffice-v2/src/common/components/molecules/GetFullAccessCard/GetFullAccessCard.tsx (1 hunks)
  • apps/backoffice-v2/src/common/components/organisms/Dialog/Dialog.Content.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/business-reports/components/BusinessReportsLeftCard/BusinessReportsLeftCard.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/business-reports/hooks/mutations/useCreateBusinessReportMutation/useCreateBusinessReportMutation.tsx (3 hunks)
  • apps/backoffice-v2/src/domains/customer/fetchers.ts (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx (3 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1 hunks)
  • services/workflows-service/src/alert/alert.service.intg.test.ts (1 hunks)
  • services/workflows-service/src/app.module.ts (2 hunks)
  • services/workflows-service/src/business-report/business-report.controller.external.ts (1 hunks)
  • services/workflows-service/src/business-report/business-report.module.ts (1 hunks)
  • services/workflows-service/src/business-report/business-report.service.ts (1 hunks)
  • services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts (1 hunks)
  • services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts (1 hunks)
  • services/workflows-service/src/common/guards/token-guard/token-auth.module.ts (1 hunks)
  • services/workflows-service/src/customer/customer.controller.external.ts (3 hunks)
  • services/workflows-service/src/customer/customer.module.ts (2 hunks)
  • services/workflows-service/src/customer/customer.service.ts (2 hunks)
  • services/workflows-service/src/customer/schemas/zod-schemas.ts (1 hunks)
  • services/workflows-service/src/end-user/end-user.controller.external.intg.test.ts (1 hunks)
  • services/workflows-service/src/global.d.ts (1 hunks)
  • services/workflows-service/src/merchant-monitoring/merchant-monitoring.module.ts (1 hunks)
  • services/workflows-service/src/workflow-defintion/workflow-definition.service.intg.test.ts (2 hunks)
  • services/workflows-service/src/workflow/workflow-runtime-data.repository.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.controller.external.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.controller.internal.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.service.intg.test.ts (1 hunks)
✅ Files skipped from review due to trivial changes (11)
  • apps/backoffice-v2/src/common/components/organisms/Dialog/Dialog.Content.tsx
  • services/workflows-service/src/end-user/end-user.controller.external.intg.test.ts
  • services/workflows-service/src/workflow/workflow-runtime-data.repository.intg.test.ts
  • services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts
  • services/workflows-service/src/workflow/workflow.controller.internal.intg.test.ts
  • services/workflows-service/src/business-report/business-report.service.ts
  • services/workflows-service/src/business-report/business-report.controller.external.ts
  • services/workflows-service/src/workflow/workflow.service.intg.test.ts
  • services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts
  • services/workflows-service/src/workflow/workflow.controller.external.intg.test.ts
  • services/workflows-service/src/alert/alert.service.intg.test.ts
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: test_windows
  • GitHub Check: test_linux
  • GitHub Check: build (windows-latest)
  • GitHub Check: lint
  • GitHub Check: build (ubuntu-latest)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: format
🔇 Additional comments (16)
services/workflows-service/src/common/guards/token-guard/token-auth.module.ts (1)

13-13:

✅ Verification successful

LGTM! Verify dependency injection order.

The addition of MerchantMonitoringClient to the TokenAuthModule aligns with the PR objectives. The import and provider registration look correct.

Let's verify there are no dependency injection issues with the new client:

Also applies to: 17-17


🏁 Script executed:

#!/bin/bash
# Description: Check for potential circular dependencies and verify the client's dependencies

# Search for MerchantMonitoringClient dependencies
ast-grep --pattern 'class MerchantMonitoringClient {
  constructor($_) {
    $$$
  }
}'

# Search for any services that might depend on MerchantMonitoringClient
rg "MerchantMonitoringClient" -A 5

Length of output: 22407


LGTM! The addition of MerchantMonitoringClient to the TokenAuthModule not only aligns with the PR objectives but also has been verified to not introduce any dependency injection issues. The search results confirm that there are no circular dependency concerns and that the provider registration order is correct.

  • Verified that the import and providers addition follow the existing structure.
  • No dependency injection issues were found based on the search output.
services/workflows-service/src/customer/customer.controller.external.ts (3)

1-1: Import of TDemoAccessDetails is on point.
No issues with referencing TDemoAccessDetails here, as it aligns with the usage later in the file for demoAccessDetails integration.


3-9: Expanded exception imports enhance error handling.
Including BadRequestException and NotFoundException is a good practice. Just ensure consistent usage across the controller to distinguish between invalid inputs (400) and absent resources (404).


88-97: Validate config before spreading additional properties.
If customer.config could be null or undefined, spreading it might cause issues. Also ensure that any direct usage of demoAccessDetails is guarded or defaulted to an empty object if none is found.

services/workflows-service/src/merchant-monitoring/merchant-monitoring.module.ts (1)

1-9: Module structure and provider export look fine.
The MerchantMonitoringModule properly encapsulates the MerchantMonitoringClient and re-exports it for usage elsewhere. Consider adding minimal tests to ensure the provider initializes correctly.

services/workflows-service/src/customer/schemas/zod-schemas.ts (2)

11-11: Verify the necessity of both isDemo and isDemoAccount properties.

The schema contains two similar boolean properties: isDemo and isDemoAccount. This might lead to confusion about which property should be used.

Consider consolidating these properties or clarifying their distinct purposes through documentation.


20-25: LGTM! Well-structured schema for demo access details.

The schema effectively captures all necessary properties for managing demo access, with appropriate types and default values.

services/workflows-service/src/business-report/business-report.module.ts (1)

17-17: LGTM! Import path updated correctly.

The import path for MerchantMonitoringClient has been properly updated to reflect its new location.

apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx (1)

17-19: Consider adding error handling for missing customer data.

The destructuring of customer?.config?.demoAccessDetails could result in undefined values if the customer data is not properly loaded.

Add null checks or provide default values:

-  const { totalReports, maxBusinessReports, expiresAt } = customer?.config?.demoAccessDetails ?? {};
+  const { totalReports = 0, maxBusinessReports = 0, expiresAt = null } = customer?.config?.demoAccessDetails ?? {};
services/workflows-service/src/customer/customer.service.ts (1)

86-88: LGTM! Type safety improvement.

The return type change from type assertion to direct type improves type safety.

apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1)

137-153: LGTM! Well-structured validation schema.

The schema has:

  • Clear error messages
  • Appropriate max length constraints
  • Optional fields where needed
services/workflows-service/src/app.module.ts (1)

94-94: LGTM! Module properly imported.

The MerchantMonitoringModule is correctly added to the imports array.

apps/backoffice-v2/src/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic.tsx (1)

180-180: LGTM! Demo access details properly exposed.

The hook correctly exposes the demo access details from the customer configuration.

apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx (1)

18-20: LGTM! Clean props interface and component structure.

The component has a clear, minimal props interface and follows React best practices with proper type definitions.

Also applies to: 70-73

services/workflows-service/src/workflow-defintion/workflow-definition.service.intg.test.ts (1)

60-60: LGTM! Proper module integration in test setup.

The MerchantMonitoringModule is correctly imported and included in the test module setup.

apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx (1)

88-88: LGTM! Consistent icon usage.

The Plus icon is more appropriate for the create action and maintains consistency with other create actions in the UI.

Comment on lines 58 to 63
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<
| (Omit<TCustomerWithFeatures, 'config'> & {
config: TCustomerWithFeatures['config'] & { demoAccessDetails: TDemoAccessDetails };
})
| null
> {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider making demoAccessDetails optional in the return type.
The method signature currently enforces demoAccessDetails in the returned config. If demoAccessDetails is not found, the code returns the customer object without that property, creating a potential type mismatch. Make demoAccessDetails optional or guarantee it always exists.

-    | (Omit<TCustomerWithFeatures, 'config'> & {
-        config: TCustomerWithFeatures['config'] & { demoAccessDetails: TDemoAccessDetails };
-      })
+    | (Omit<TCustomerWithFeatures, 'config'> & {
+        config: TCustomerWithFeatures['config'] & { demoAccessDetails?: TDemoAccessDetails };
+      })
📝 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
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<
| (Omit<TCustomerWithFeatures, 'config'> & {
config: TCustomerWithFeatures['config'] & { demoAccessDetails: TDemoAccessDetails };
})
| null
> {
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<
| (Omit<TCustomerWithFeatures, 'config'> & {
config: TCustomerWithFeatures['config'] & { demoAccessDetails?: TDemoAccessDetails };
})
| null
> {

Comment on lines +13 to +14
// FIXME: this is a problem

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add context to the FIXME comment.

The FIXME comment lacks explanation about what the problem is, making it difficult for other developers to understand and address the issue.

Please elaborate on the problem and potential solutions in the comment.

Comment on lines +31 to +39
const { mutate: mutateCreateBusinessReport, isLoading: isSubmitting } =
useCreateBusinessReportMutation({ disableToast: true });
const onSubmit: SubmitHandler<CreateBusinessReportDialogInput> = data => {
mutateCreateBusinessReport(data, {
onSuccess: () => {
setShowSuccess(true);
},
});
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling in the onSubmit callback.

The mutation's error case is not handled in the component level, which might lead to a poor user experience if the mutation fails.

Add error handling:

   const onSubmit: SubmitHandler<CreateBusinessReportDialogInput> = data => {
     mutateCreateBusinessReport(data, {
       onSuccess: () => {
         setShowSuccess(true);
       },
+      onError: () => {
+        setShowSuccess(false);
+      },
     });
   };
📝 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
const { mutate: mutateCreateBusinessReport, isLoading: isSubmitting } =
useCreateBusinessReportMutation({ disableToast: true });
const onSubmit: SubmitHandler<CreateBusinessReportDialogInput> = data => {
mutateCreateBusinessReport(data, {
onSuccess: () => {
setShowSuccess(true);
},
});
};
const { mutate: mutateCreateBusinessReport, isLoading: isSubmitting } =
useCreateBusinessReportMutation({ disableToast: true });
const onSubmit: SubmitHandler<CreateBusinessReportDialogInput> = data => {
mutateCreateBusinessReport(data, {
onSuccess: () => {
setShowSuccess(true);
},
onError: () => {
setShowSuccess(false);
},
});
};

Comment on lines +21 to +28
const form = useForm({
defaultValues: {
websiteUrl: '',
companyName: undefined,
businessCorrelationId: undefined,
},
resolver: zodResolver(CreateBusinessReportDialogSchema),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider adding validation for businessCorrelationId.

The form's default values include businessCorrelationId but there's no visible validation in the schema import.

Please verify that CreateBusinessReportDialogSchema includes proper validation for all fields:


🏁 Script executed:

#!/bin/bash
# Search for the schema definition
rg -A 10 "CreateBusinessReportDialogSchema.*=.*" 

Length of output: 999


Action Required: Add Explicit Validation for businessCorrelationId

After examining the schema, it appears that while the field businessCorrelationId is declared in the CreateBusinessReportDialogSchema, no explicit validation rules (e.g., type constraints or pattern checks) are applied to it. Please update this field with appropriate validation (for instance, if it should be a UUID or match a specific pattern, chain the corresponding Zod methods).

  • Location: apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (see the partial definition for businessCorrelationId)
  • Recommendation: Extend the validation for businessCorrelationId (e.g., using z.string().uuid().optional() or any other validation that aligns with your business requirements).

Comment on lines +41 to +48
demoAccessDetails: z
.object({
expiresAt: z.number().optional(),
showFullAccessPopup: z.boolean().optional(),
totalReports: z.number(),
maxBusinessReports: z.number(),
})
.optional(),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding validation constraints for demo access details.

The schema lacks validation for reasonable value ranges for totalReports, maxBusinessReports, and expiresAt.

Add validation constraints:

       demoAccessDetails: z
         .object({
-          expiresAt: z.number().optional(),
+          expiresAt: z.number().min(Date.now() / 1000).optional(),
           showFullAccessPopup: z.boolean().optional(),
-          totalReports: z.number(),
+          totalReports: z.number().min(0),
-          maxBusinessReports: z.number(),
+          maxBusinessReports: z.number().min(1),
         })
📝 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
demoAccessDetails: z
.object({
expiresAt: z.number().optional(),
showFullAccessPopup: z.boolean().optional(),
totalReports: z.number(),
maxBusinessReports: z.number(),
})
.optional(),
demoAccessDetails: z
.object({
expiresAt: z.number().min(Date.now() / 1000).optional(),
showFullAccessPopup: z.boolean().optional(),
totalReports: z.number().min(0),
maxBusinessReports: z.number().min(1),
})
.optional(),

@@ -10,6 +10,8 @@ declare module '@prisma/client' {
import type { TCustomerConfig, TCustomerSubscription } from '@/customer/schemas/zod-schemas';
export * from '@prisma/client/index';

// FIXME: this is a problem
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the problem? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

image
image

maybe i'm missing something, but these types do not resolve to anything for me, i don't see them being imported. so i wonder how is this supposed to work? our types depend on these but they are literally any?

totalReports: businessReportsCount,
maxBusinessReports: config.maxBusinessReports ?? 10,
showFullAccessPopup: config.showFullAccessPopup ?? false,
// FIXME: should count from the first login date / should be passed on creation ?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I recommend you to discuss it with @ArtemLavrentii, as he's working on the customer's email onboarding and signup.
We wanted it to start counting since the user was signed it first time. But we can also compromise on the customer creation date, as you did. It depends on the effort. I think Artem can help make a decision here.

Copy link
Collaborator

@ArtemLavrentii ArtemLavrentii Feb 18, 2025

Choose a reason for hiding this comment

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

Do we expect for people to not sign in for multiple days? Creation date of a user wouldn't be when they send a request, but rather when they get the email / its get approved by the risk team.

We can also add first sign in date to a user, shouldn't be too hard to implement. I'm just unsure how useful it would be outside of demo. Maybe we could include that info in the customer config if isDemoAccount is set, wdyt ? ( we could even do it as "expiresAt" - eg just set it when user first logs in, if its not present

});

return {
totalReports: businessReportsCount,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have a mechanism in the front-end the ensure this property gets updated when reports are added?

Copy link
Collaborator

Choose a reason for hiding this comment

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

And just a quick comment: Ideally, this shouldn’t be under customers and should have its own endpoint, like GET /api/business-reports/count. But since it’s just for a demo, it's not a big deal

maxBusinessReports: config.maxBusinessReports ?? 10,
showFullAccessPopup: config.showFullAccessPopup ?? false,
// FIXME: should count from the first login date / should be passed on creation ?
expiresAt: dayjs(createdAt).add(14, 'days').unix(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's add a new expiresAt property in the config. This way we could easily change the expiration date manually. I also suggest moving the number 14 to the env.ts file.

async getByCurrentProjectId(
@CurrentProject() currentProjectId: TProjectId,
): Promise<TCustomerWithFeatures | null> {
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<
Copy link
Collaborator

@ArtemLavrentii ArtemLavrentii Feb 18, 2025

Choose a reason for hiding this comment

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

Wouldn't something like this also work ?

Suggested change
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<
async getByCurrentProjectId(@CurrentProject() currentProjectId: TProjectId): Promise<(TCustomerWithFeatures & { config: { demoAccessDetails: TDemoAccessDetails } } ) | null>

In either case I would create separate type for TCustomerWithFeatures with demo access details so the return type isn't as messy.

@@ -15,7 +15,7 @@ export const GetFullAccessCard = () => {
if (
env.VITE_ENVIRONMENT_NAME === 'production' ||
Copy link
Collaborator

Choose a reason for hiding this comment

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

We are going to create the demo accounts in production, and not sandbox this time, as this environment is more stable. Can you please remove this condition and make sure it works well on a production environment?

Context: https://teamballerine.slack.com/archives/C06MQM4F17D/p1739886859740529

maxBusinessReports: config.maxBusinessReports ?? 10,
showFullAccessPopup: config.showFullAccessPopup ?? false,
// FIXME: should count from the first login date / should be passed on creation ?
expiresAt: dayjs(createdAt).add(14, 'days').unix(),
Copy link
Collaborator

@MatanYadaev MatanYadaev Feb 18, 2025

Choose a reason for hiding this comment

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

We usually use ISO format, please don't introduce new conventions (Unix timestamp) as it makes the source code confusing and inconsistent.

Comment on lines +131 to +132
const URL_REGEX =
/((https?):\/\/)?([a-zA-Z0-9-_]+\.)+[a-zA-Z0-9]+(\.[a-z]{2})?(\/[a-zA-Z0-9_#-]+)*(\/)?(\?[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+(&[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*)?(#[a-zA-Z0-9_-]+)?/;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Move it to @ballerine/common and reuse it in the WFS?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We also use it in other places as well.

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.

Actionable comments posted: 0

♻️ Duplicate comments (3)
apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx (1)

33-39: ⚠️ Potential issue

Add error handling in the onSubmit callback.

The mutation's error case is not handled in the component level.

   const onSubmit: SubmitHandler<CreateBusinessReportDialogInput> = data => {
     mutateCreateBusinessReport(data, {
       onSuccess: () => {
         setShowSuccess(true);
       },
+      onError: error => {
+        setShowSuccess(false);
+        // Consider adding error state management here
+      },
     });
   };
apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1)

131-132: 🛠️ Refactor suggestion

Move URL_REGEX to @ballerine/common package.

The URL_REGEX could be reused across different parts of the application.

Consider moving this regex to @ballerine/common package for reuse in other places, including the Workflow Service.

services/workflows-service/src/customer/customer.service.ts (1)

24-42: 💡 Verification agent

⚠️ Potential issue

🧩 Analysis chain

Multiple improvements needed in demo access details implementation.

  1. The expiration date is using Unix timestamp format while the codebase convention is to use ISO format.
  2. The magic number 14 for demo expiration days should be moved to env.ts.
  3. The expiration calculation from creation date needs reconsideration.

Apply these improvements:

+// In env.ts
+DEMO_EXPIRATION_DAYS=14

+// In customer.service.ts
 async getDemoAccessDetails(customer: TCustomerWithFeatures): Promise<TDemoAccessDetails | null> {
   const { id: customerId, config, createdAt } = customer;

   if (!config || !config.isDemoAccount || !createdAt) {
     return null;
   }

   const businessReportsCount = await this.merchantMonitoringClient.count({
     customerId,
   });

   return {
     totalReports: businessReportsCount,
     maxBusinessReports: config.maxBusinessReports ?? 10,
     showFullAccessPopup: config.showFullAccessPopup ?? false,
-    // FIXME: should count from the first login date / should be passed on creation ?
-    expiresAt: dayjs(createdAt).add(14, 'days').unix(),
+    expiresAt: dayjs(createdAt).add(env.DEMO_EXPIRATION_DAYS, 'days').toISOString(),
   };
 }

Additionally, consider:

  1. Adding a firstLoginDate field to the customer config for more accurate expiration calculation
  2. Moving the business reports count to a dedicated endpoint for better separation of concerns

🏁 Script executed:

#!/bin/bash
# Check if any other parts of the codebase use Unix timestamp format
rg -l "\.unix\(\)" 

Length of output: 119


Multiple improvements needed in demo access details implementation

  • Change the expiration date format from a Unix timestamp to ISO format to align with our project's standard.
  • Replace the hardcoded magic number 14 with a configurable environment variable (e.g., env.DEMO_EXPIRATION_DAYS) to improve maintainability.
  • Reevaluate whether calculating the expiration based on the customer creation date is correct—consider using a firstLoginDate if that better reflects the intended behavior.
  • As an additional note, our codebase’s main.ts still uses .unix() for date conversion. Ensure that switching to ISO formatting here won’t lead to inconsistency or unexpected behavior across the system.
// In env.ts
+export const DEMO_EXPIRATION_DAYS = 14;

...
// In services/workflows-service/src/customer/customer.service.ts
 async getDemoAccessDetails(customer: TCustomerWithFeatures): Promise<TDemoAccessDetails | null> {
   const { id: customerId, config, createdAt } = customer;

   if (!config || !config.isDemoAccount || !createdAt) {
     return null;
   }

   const businessReportsCount = await this.merchantMonitoringClient.count({
     customerId,
   });

   return {
     totalReports: businessReportsCount,
     maxBusinessReports: config.maxBusinessReports ?? 10,
     showFullAccessPopup: config.showFullAccessPopup ?? false,
-    // FIXME: should count from the first login date / should be passed on creation ?
-    expiresAt: dayjs(createdAt).add(14, 'days').unix(),
+    // FIXME: consider using firstLoginDate for a more accurate expiration calculation
+    expiresAt: dayjs(createdAt).add(env.DEMO_EXPIRATION_DAYS, 'days').toISOString(),
   };
 }
🧹 Nitpick comments (8)
apps/backoffice-v2/src/domains/business-reports/components/BusinessReportsLeftCard/BusinessReportsLeftCard.tsx (3)

16-23: Simplify null/undefined checks using nullish coalescing.

The null and undefined checks can be simplified for better readability.

-  if (
-    reportsLeft === null ||
-    demoDaysLeft === null ||
-    reportsLeft === undefined ||
-    demoDaysLeft === undefined
-  ) {
+  if (reportsLeft == null || demoDaysLeft == null) {
     return null;
   }

25-25: Improve state determination readability using descriptive variables.

The state determination logic could be more readable by breaking it down into descriptive variables.

-  const state = demoDaysLeft <= 0 ? 'expired' : reportsLeft <= 0 ? 'noReports' : 'active';
+  const isExpired = demoDaysLeft <= 0;
+  const hasNoReports = reportsLeft <= 0;
+  const state = isExpired ? 'expired' : hasNoReports ? 'noReports' : 'active';

27-36: Extract message strings as constants.

Consider extracting the message strings as constants to improve maintainability and reusability.

+const MESSAGES = {
+  EXPIRED: 'Your demo account has expired!',
+  NO_REPORTS: 'You don\'t have any reports left!',
+  REPORTS_LEFT: 'free reports',
+  DAYS_LEFT: 'days.',
+} as const;

 const messages: Record<string, ReactNode> = {
-  expired: <span className="text-destructive">Your demo account has expired!</span>,
+  expired: <span className="text-destructive">{MESSAGES.EXPIRED}</span>,
-  noReports: <span className="text-destructive">You don&apos;t have any reports left!</span>,
+  noReports: <span className="text-destructive">{MESSAGES.NO_REPORTS}</span>,
   active: (
     <span>
-      You have <span className="font-bold">{reportsLeft} free reports</span> left to create,
-      available for <span className="font-bold">{demoDaysLeft} days.</span>
+      You have <span className="font-bold">{reportsLeft} {MESSAGES.REPORTS_LEFT}</span> left to create,
+      available for <span className="font-bold">{demoDaysLeft} {MESSAGES.DAYS_LEFT}</span>
     </span>
   ),
 };
apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx (1)

17-19: Improve data destructuring with default values.

The destructuring of customer data could be more robust with default values.

-  const { totalReports, maxBusinessReports, expiresAt } = customer?.config?.demoAccessDetails ?? {};
-  const reportsLeft = maxBusinessReports && totalReports ? maxBusinessReports - totalReports : null;
-  const demoDaysLeft = expiresAt ? dayjs(expiresAt * 1000).diff(dayjs(), 'days') : null;
+  const { 
+    totalReports = 0, 
+    maxBusinessReports = 0, 
+    expiresAt = 0 
+  } = customer?.config?.demoAccessDetails ?? {};
+  const reportsLeft = maxBusinessReports - totalReports;
+  const demoDaysLeft = dayjs(expiresAt * 1000).diff(dayjs(), 'days');
services/workflows-service/src/customer/types.ts (1)

66-68: Add documentation for the demo customer type.

Consider adding JSDoc comments to document the purpose and structure of the TDemoCustomer type, especially since it's a key type for demo functionality.

+/**
+ * Represents a customer with demo access capabilities.
+ * Extends the base customer type by replacing the config property
+ * with one that includes optional demo access details.
+ */
 export type TDemoCustomer = Omit<TCustomerWithFeatures, 'config'> & {
   config: { demoAccessDetails?: TDemoAccessDetails };
 };
services/workflows-service/src/customer/customer.service.ts (1)

86-88: Simplify type assertion in getByProjectId.

The type assertion can be moved to the repository layer for better type safety.

 async getByProjectId(projectId: string, args?: Omit<Prisma.CustomerFindFirstArgsBase, 'where'>) {
-  return (await this.repository.findByProjectId(projectId, args)) as TCustomerWithFeatures;
+  return await this.repository.findByProjectId(projectId, args);
 }
services/workflows-service/src/customer/customer.controller.external.ts (2)

55-60: Update Swagger documentation for the demo customer response.

The Swagger response type needs to be updated to reflect the new return type.

 @common.Get('/by-current-project-id')
-@swagger.ApiOkResponse({ type: [CustomerModel] })
+@swagger.ApiOkResponse({ 
+  type: CustomerModel,
+  description: 'Returns customer information with demo access details if applicable' 
+})
 @swagger.ApiForbiddenResponse()
+@swagger.ApiNotFoundResponse({ description: 'Customer not found' })
 async getByCurrentProjectId(
   @CurrentProject() currentProjectId: TProjectId,
 ): Promise<TDemoCustomer>

81-83: Use NotFoundException for consistency.

The error handling should use NotFoundException consistently throughout the controller.

 if (!customer) {
-  throw new BadRequestException('Customer not found');
+  throw new NotFoundException('Customer not found');
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cf4fca and 7736dc5.

📒 Files selected for processing (31)
  • apps/backoffice-v2/src/common/components/molecules/GetFullAccessCard/GetFullAccessCard.tsx (1 hunks)
  • apps/backoffice-v2/src/common/components/organisms/Dialog/Dialog.Content.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/business-reports/components/BusinessReportsLeftCard/BusinessReportsLeftCard.tsx (1 hunks)
  • apps/backoffice-v2/src/domains/business-reports/hooks/mutations/useCreateBusinessReportMutation/useCreateBusinessReportMutation.tsx (3 hunks)
  • apps/backoffice-v2/src/domains/customer/fetchers.ts (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx (3 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/hooks/useCreateMerchantReportDialogLogic.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic.tsx (1 hunks)
  • apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1 hunks)
  • services/workflows-service/src/alert/alert.service.intg.test.ts (1 hunks)
  • services/workflows-service/src/app.module.ts (2 hunks)
  • services/workflows-service/src/business-report/business-report.controller.external.ts (1 hunks)
  • services/workflows-service/src/business-report/business-report.module.ts (1 hunks)
  • services/workflows-service/src/business-report/business-report.service.ts (1 hunks)
  • services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts (1 hunks)
  • services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts (1 hunks)
  • services/workflows-service/src/common/guards/token-guard/token-auth.module.ts (1 hunks)
  • services/workflows-service/src/customer/customer.controller.external.ts (4 hunks)
  • services/workflows-service/src/customer/customer.module.ts (2 hunks)
  • services/workflows-service/src/customer/customer.service.ts (2 hunks)
  • services/workflows-service/src/customer/schemas/zod-schemas.ts (1 hunks)
  • services/workflows-service/src/customer/types.ts (2 hunks)
  • services/workflows-service/src/end-user/end-user.controller.external.intg.test.ts (1 hunks)
  • services/workflows-service/src/global.d.ts (1 hunks)
  • services/workflows-service/src/merchant-monitoring/merchant-monitoring.module.ts (1 hunks)
  • services/workflows-service/src/workflow-defintion/workflow-definition.service.intg.test.ts (2 hunks)
  • services/workflows-service/src/workflow/workflow-runtime-data.repository.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.controller.external.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.controller.internal.intg.test.ts (1 hunks)
  • services/workflows-service/src/workflow/workflow.service.intg.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (25)
  • apps/backoffice-v2/src/common/components/organisms/Dialog/Dialog.Content.tsx
  • services/workflows-service/src/merchant-monitoring/merchant-monitoring.module.ts
  • services/workflows-service/src/app.module.ts
  • services/workflows-service/src/workflow/workflow.service.intg.test.ts
  • services/workflows-service/src/workflow-defintion/workflow-definition.service.intg.test.ts
  • apps/backoffice-v2/src/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic.tsx
  • services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts
  • services/workflows-service/src/business-report/business-report.service.ts
  • services/workflows-service/src/workflow/workflow-runtime-data.repository.intg.test.ts
  • services/workflows-service/src/customer/customer.module.ts
  • services/workflows-service/src/end-user/end-user.controller.external.intg.test.ts
  • services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts
  • services/workflows-service/src/workflow/workflow.controller.external.intg.test.ts
  • apps/backoffice-v2/src/pages/MerchantMonitoring/MerchantMonitoring.page.tsx
  • services/workflows-service/src/business-report/business-report.module.ts
  • apps/backoffice-v2/src/common/components/molecules/GetFullAccessCard/GetFullAccessCard.tsx
  • services/workflows-service/src/business-report/business-report.controller.external.ts
  • services/workflows-service/src/alert/alert.service.intg.test.ts
  • apps/backoffice-v2/src/domains/customer/fetchers.ts
  • services/workflows-service/src/customer/schemas/zod-schemas.ts
  • services/workflows-service/src/global.d.ts
  • apps/backoffice-v2/src/pages/MerchantMonitoring/components/CreateMerchantReportDialog/CreateMerchantReportDialog.tsx
  • services/workflows-service/src/common/guards/token-guard/token-auth.module.ts
  • services/workflows-service/src/workflow/workflow.controller.internal.intg.test.ts
  • apps/backoffice-v2/src/domains/business-reports/hooks/mutations/useCreateBusinessReportMutation/useCreateBusinessReportMutation.tsx
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: test_windows
  • GitHub Check: test_linux
  • GitHub Check: build (windows-latest)
  • GitHub Check: build (ubuntu-latest)
  • GitHub Check: lint
  • GitHub Check: format
🔇 Additional comments (1)
apps/backoffice-v2/src/pages/MerchantMonitoring/schemas.ts (1)

135-151: Enhance validation for businessCorrelationId.

The validation for businessCorrelationId could be more specific.

Consider adding more specific validation rules for businessCorrelationId (e.g., UUID format, specific pattern) based on your business requirements.

   businessCorrelationId: z
     .string({
       invalid_type_error: 'Business ID must be a string',
     })
     .max(255)
+    .regex(/^[a-zA-Z0-9-_]+$/, {
+      message: 'Business ID can only contain letters, numbers, hyphens, and underscores',
+    })
     .optional(),

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.

3 participants