Skip to content

Instantly share code, notes, and snippets.

@jay-babu
Created September 23, 2025 20:51
Show Gist options
  • Select an option

  • Save jay-babu/2888ec0e72b82c500a1dc2b9cf170314 to your computer and use it in GitHub Desktop.

Select an option

Save jay-babu/2888ec0e72b82c500a1dc2b9cf170314 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 4592182d..9f305e06 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -1,8 +1,7 @@
{
"permissions": {
"allow": [
- "Bash(grep:*)",
- "Bash(npm test:*)"
+ "Bash(grep:*)"
],
"deny": []
},
diff --git a/.env.development b/.env.development
index 7fb2fe6d..3eaacafb 100644
--- a/.env.development
+++ b/.env.development
@@ -1,6 +1,4 @@
-VITE_APP_API_URL=http://localhost:8080
-# VITE_APP_API_URL=https://dev.api.transformity.tech
-# VITE_APP_API_URL=https://api.transformity.tech
+VITE_APP_API_URL=http://localhost:8080 # https://dev.api.transformity.tech
VITE_APP_PUBLIC_POSTHOG_KEY=phc_sr0PGw2BOIuoyKjJy3I7Jp4I9WCxXjEs3d1JbZJIJy4
VITE_APP_PUBLIC_POSTHOG_HOST=https://djyhwry6chcok.cloudfront.net
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51RLs6OD7Vv3KEo8tiRoLtYecfpUdYGbjpV8O1StUCrSLlHLj8FG67wzbJo0r9JAd30EbPlN3ubmVsl0ZwrP6mxVt0004CL9PvY
@@ -10,7 +8,3 @@ VITE_APP_QUILL_COHORT_PUBLIC_KEY=66e9b50d131e7b000bd5fadf
VITE_APP_QUILL_ENTITY_PUBLIC_KEY=66e9b50d131e7b000bd5fadf
VITE_APP_PAYRIX_PUBLIC_KEY=2e43da0fa5560fe20d8d386e7b9fd155
VITE_APP_PAYRIX_URL=https://test-api.payrix.com
-VITE_APP_ZEUS_URL=https://zeus.usemargin.dev
-# VITE_APP_ZEUS_URL=http://localhost:9090
-VITE_APP_PHOENIX_URL=https://d338aujdgql5cv.cloudfront.net
-VITE_APP_PUBLIC_STATSIG_CLIENT_KEY=client-eRuybgghH4DCiONufndDbCFW3LDLxnLg1hU38YbAI55
diff --git a/.env.production b/.env.production
index 5fabf3e6..c723ef8b 100644
--- a/.env.production
+++ b/.env.production
@@ -6,4 +6,3 @@ VITE_APP_QUILL_COHORT_PUBLIC_KEY=66e9c30e131e7b000bd62af7
VITE_APP_QUILL_ENTITY_PUBLIC_KEY=66ff8a2cedc87e000be77866
VITE_APP_PAYRIX_PUBLIC_KEY=4804148321779a32edc8948702233442
VITE_APP_PAYRIX_URL=https://api.payrix.com
-VITE_APP_PUBLIC_STATSIG_CLIENT_KEY=client-eRuybgghH4DCiONufndDbCFW3LDLxnLg1hU38YbAI55
diff --git a/.prettierrc.json b/.prettierrc.json
index fc362149..55c1943a 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1,3 +1,3 @@
{
- "plugins": ["@prettier/plugin-oxc", "prettier-plugin-organize-imports"]
+ "plugins": ["prettier-plugin-organize-imports"]
}
diff --git a/CRUSH.md b/CRUSH.md
index a8e45596..8e0bbf1e 100644
--- a/CRUSH.md
+++ b/CRUSH.md
@@ -34,16 +34,6 @@
**Hardware:** Receipt printing via WebSerial/WebUSB APIs. Barcode scanning via webhid-barcode-scanner.
-## UX/Design Principles
-
-**Smooth Transitions:** Prioritize polished user experiences with CSS transitions over abrupt state changes. Prevent UI jitters with morphing containers and adaptive layouts.
-
-**Information Preservation:** Keep users informed during loading states - show current data with loading indicators rather than hiding content.
-
-**Professional POS Standards:** Solutions must feel enterprise-grade for retail/hospitality. Maintain existing design systems while improving behavior.
-
-**Problem-Solving Process:** Use v0 for brainstorming multiple approaches with pros/cons before implementing. Consider real-world POS usage scenarios.
-
## Cursor Rules Integration
Follow `.cursor/rules/core.mdc` principles: verify before changing, use workspace-relative paths for edits, prioritize reusability.
diff --git a/POSServiceModel b/POSServiceModel
index d732267c..1d26bce3 160000
--- a/POSServiceModel
+++ b/POSServiceModel
@@ -1 +1 @@
-Subproject commit d732267c11242488a61ec7697e50151c7a2aa438
+Subproject commit 1d26bce3aa66370e48b8d816d73b889a2086f4c4
diff --git a/Pulumi.beta.yaml b/Pulumi.beta.yaml
index 23a5500b..554dc411 100644
--- a/Pulumi.beta.yaml
+++ b/Pulumi.beta.yaml
@@ -1,5 +1,2 @@
-config:
- aws:region: us-east-1
- domain: pos.beta.transformity.tech
secretsprovider: awskms://alias/pulumi-production?region=us-east-1
encryptedkey: AQICAHgW5CflR2+hwkIP9fktbEu4lWc/+eDpIVQFzsK4gQ/4jAGoJHcy7wgufaEUWYywsrSeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM4apEm63r8/TEc58fAgEQgDu0BYl0Ds4IihI3ETcRMSI1kBZ2jQk/vplRt1NLV/mxJGbqAJYbWZ3qcXuwrQJ8ua+VBj0W5SQIP+ZRdg==
diff --git a/Pulumi.gamma.yaml b/Pulumi.gamma.yaml
index 7bd23ffa..17cd80dc 100644
--- a/Pulumi.gamma.yaml
+++ b/Pulumi.gamma.yaml
@@ -1,5 +1,4 @@
config:
aws:region: us-east-1
- domain: dev.pos.transformity.tech
secretsprovider: awskms://alias/pulumi-gamma?region=us-east-1
encryptedkey: AQICAHhl5kPDyg+7mJXABM7RtmPC6Q7j6ZQpqxejHGBgEvasxAG1SalUPbQ5aGcDJa3bVqu3AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMvmetfZzSFmVgupY8AgEQgDtypZUSSpk1naBdUmOFfIpJp/Ebm19ZBc1xfucZ11DYF8aZLJVYzX59o+2G18QiVHFO1b/kdbkrqweg3A==
diff --git a/Pulumi.prod.yaml b/Pulumi.prod.yaml
index c5482b69..00edbc7a 100644
--- a/Pulumi.prod.yaml
+++ b/Pulumi.prod.yaml
@@ -1,5 +1,2 @@
-config:
- aws:region: us-east-1
- domain: pos.transformity.tech
secretsprovider: awskms://alias/pulumi-production?region=us-east-1
encryptedkey: AQICAHgW5CflR2+hwkIP9fktbEu4lWc/+eDpIVQFzsK4gQ/4jAEO0WS/feDuFf6S5LCVMJcnAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMmoxu0ii2FiXr9Mm9AgEQgDvVTrrashM0MSWHYOlpgoY3jOUHAiBHD54lP7PZHfRGYTT0Ge+tJhyhUyLd/FxeJbjVDonIvS1YR3bz9A==
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 31fe81ad..ef1e7ad2 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -55,7 +55,6 @@ export default defineConfig([
},
rules: {
"@typescript-eslint/no-floating-promises": "error",
- "react-hooks/exhaustive-deps": "error",
},
},
]);
diff --git a/index.ts b/index.ts
index 6d6bc6c5..5f863480 100644
--- a/index.ts
+++ b/index.ts
@@ -5,51 +5,22 @@ import * as fs from "fs";
import * as path from "path";
import { cwd } from "process";
+const org = pulumi.getOrganization();
const stack = pulumi.getStack();
-const config = new pulumi.Config();
+
+const backendStack = new pulumi.StackReference(
+ `${org}/pos-backend/${stack === "prod" ? "production" : stack}`,
+);
+const wildcardCertificate = backendStack
+ .getOutput("wildcardCertificate")
+ .apply((cert: aws.acm.Certificate) => cert);
+
const getBranches = (
stack: string,
appId: Output<string>,
): { branch: aws.amplify.Branch; name: string }[] => {
switch (stack) {
case "beta":
- return [
- {
- branch: new aws.amplify.Branch(
- "pos-frontend-amplify-branch-prod",
- {
- appId: appId,
- branchName: "release",
- displayName: "release",
- framework: "React",
- region: "us-east-1",
- stage: "PRODUCTION",
- ttl: "5",
- },
- {
- protect: true,
- },
- ),
- name: "CANARY",
- },
- {
- branch: new aws.amplify.Branch(
- "pos-frontend-amplify-branch-beta",
- {
- appId: appId,
- branchName: "beta",
- displayName: "beta",
- region: "us-east-1",
- stage: "BETA",
- ttl: "5",
- },
- {
- protect: true,
- },
- ),
- name: "STABLE",
- },
- ];
case "prod":
return [
{
@@ -84,14 +55,14 @@ const getBranches = (
"https://beta.sale.api.transformity.tech",
},
region: "us-east-1",
- stage: "BETA",
+ stage: "NONE",
ttl: "5",
},
{
protect: true,
},
),
- name: "CANARY",
+ name: "BETA",
},
];
case "gamma":
@@ -120,7 +91,7 @@ const getBranches = (
stage: "PRODUCTION",
ttl: "5",
}),
- name: "CANARY",
+ name: "BETA",
},
];
default:
@@ -201,7 +172,7 @@ const getAmplify = (stack: string) => {
jobConfig: {
buildComputeType: "LARGE_16GB",
},
- name: `TransformityPOSFrontend-${stack}`,
+ name: "TransformityPOSFrontend",
platform: "WEB",
region: "us-east-1",
repository: "https://github.com/Transformity/TransformityPOSFrontend",
@@ -211,91 +182,28 @@ const getAmplify = (stack: string) => {
},
);
case "beta":
- return new aws.amplify.App(
- "pos-frontend-amplify-beta",
- {
- buildSpec: `version: 1
-frontend:
- phases:
- preBuild:
- commands:
- - export NODE_OPTIONS=--max-old-space-size=8192
- - npm ci --cache .npm --prefer-offline
- build:
- commands:
- - npm run build
- artifacts:
- baseDirectory: build
- files:
- - "**/*"
- paths:
- - .npm/**/*
- - node_modules/**/*
- - node_modules/.vite/**/*
- `,
- cacheConfig: {
- type: "AMPLIFY_MANAGED_NO_COOKIES",
- },
- customRules: [
- {
- source: "/<*>",
- status: "404-200",
- target: "/index.html",
- },
- ],
- environmentVariables: {
- NODE_OPTIONS: "--max_old_space_size=4096",
- SENTRY_AUTH_TOKEN:
- "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",
- VITE_APP_API_URL: "https://beta.production.api.transformity.tech",
- VITE_APP_PHOENIX_URL: "https://d1la6gp2rlyhl5.cloudfront.net",
- VITE_APP_SALE_API_URL: "https://beta.sale.api.transformity.tech",
- VITE_APP_WEBSOCKET_URL:
- "wss://7c0kxkslb9.execute-api.us-east-1.amazonaws.com/$default/",
- VITE_APP_ZEUS_URL: "https://zeus.usemargin.com",
- _LIVE_UPDATES: JSON.stringify([
- {
- name: "Node.js version",
- pkg: "node",
- type: "nvm",
- version: "20",
- },
- ]),
- },
- jobConfig: {
- buildComputeType: "LARGE_16GB",
- },
- name: `TransformityPOSFrontend-${stack}`,
- platform: "WEB",
- region: "us-east-1",
- repository: "https://github.com/Transformity/TransformityPOSFrontend",
- },
- {
- protect: true,
- },
- );
case "prod":
return new aws.amplify.App(
"pos-frontend-amplify-prod",
{
buildSpec: `version: 1
-frontend:
- phases:
- preBuild:
- commands:
- - export NODE_OPTIONS=--max-old-space-size=8192
- - npm ci --cache .npm --prefer-offline
- build:
- commands:
- - npm run build
- artifacts:
- baseDirectory: build
- files:
- - '**/*'
- paths:
- - .npm/**/*
- - node_modules/**/*
- - node_modules/.vite/**/* # Vite
+ frontend:
+ phases:
+ preBuild:
+ commands:
+ - export NODE_OPTIONS=--max-old-space-size=8192
+ - npm ci --cache .npm --prefer-offline
+ build:
+ commands:
+ - npm run build
+ artifacts:
+ baseDirectory: build
+ files:
+ - '**/*'
+ paths:
+ - .npm/**/*
+ - node_modules/**/*
+ - node_modules/.vite/**/* # Vite
`,
cacheConfig: {
type: "AMPLIFY_MANAGED",
@@ -335,7 +243,6 @@ frontend:
VITE_APP_SALE_API_URL: "https://api.transformity.tech",
VITE_APP_WEBSOCKET_URL:
"wss://7c0kxkslb9.execute-api.us-east-1.amazonaws.com/$default/",
- VITE_APP_PHOENIX_URL: "https://d1la6gp2rlyhl5.cloudfront.net",
VITE_APP_ZEUS_URL: "https://zeus.usemargin.com",
_LIVE_UPDATES: JSON.stringify([
{
@@ -349,7 +256,7 @@ frontend:
jobConfig: {
buildComputeType: "LARGE_16GB",
},
- name: `TransformityPOSFrontend-${stack}`,
+ name: "TransformityPOSFrontend",
platform: "WEB",
region: "us-east-1",
repository: "https://github.com/Transformity/TransformityPOSFrontend",
@@ -363,15 +270,6 @@ frontend:
}
};
-const getCookieStackName = (stack: string) => {
- switch (stack) {
- case "beta":
- return "prod";
- default:
- return stack;
- }
-};
-
const amplify = getAmplify(stack);
const branches = getBranches(stack, amplify.id);
@@ -411,16 +309,12 @@ const lambdaEdgePolicy = new aws.iam.RolePolicyAttachment(
},
);
-const originRouterCode = fs.readFileSync(
+// Read the Lambda function code
+const lambdaCode = fs.readFileSync(
path.join(cwd(), "lambda-edge/origin-router.js"),
"utf8",
);
-const originResponseCode = fs.readFileSync(
- path.join(cwd(), "lambda-edge/origin-response.js"),
- "utf8",
-);
-
// Create Lambda@Edge function for origin routing
const originRouterLambda = new aws.lambda.Function(
`origin-router-${stack}`,
@@ -429,7 +323,7 @@ const originRouterLambda = new aws.lambda.Function(
handler: "index.handler",
role: lambdaEdgeRole.arn,
code: new pulumi.asset.AssetArchive({
- "index.js": new pulumi.asset.StringAsset(originRouterCode),
+ "index.js": new pulumi.asset.StringAsset(lambdaCode),
}),
timeout: 5,
memorySize: 128,
@@ -442,324 +336,48 @@ const originRouterLambda = new aws.lambda.Function(
},
);
-// Create Lambda@Edge function for origin response
-const originResponseLambda = new aws.lambda.Function(
- `origin-response-${stack}`,
- {
- runtime: "nodejs18.x",
- handler: "index.handler",
- role: lambdaEdgeRole.arn,
- code: new pulumi.asset.AssetArchive({
- "index.js": new pulumi.asset.StringAsset(originResponseCode),
- }),
- timeout: 5,
- memorySize: 128,
- publish: true, // Required for Lambda@Edge
- // Note: Lambda@Edge cannot have environment variables
- },
- {
- provider: usEast1Provider, // Must be in us-east-1 for Lambda@Edge
- dependsOn: [lambdaEdgePolicy],
- },
-);
-
-// Get the qualified ARNs (with version) for Lambda@Edge
-const originRouterVersionArn = pulumi.interpolate`${originRouterLambda.arn}:${originRouterLambda.version}`;
-const originResponseVersionArn = pulumi.interpolate`${originResponseLambda.arn}:${originResponseLambda.version}`;
-
-// Create Response Headers Policy to allow custom headers from Lambda@Edge
-const responseHeadersPolicy = new aws.cloudfront.ResponseHeadersPolicy(
- `pos-frontend-response-headers-${stack}`,
- {
- name: `pos-frontend-response-headers-${stack}`,
- customHeadersConfig: {
- items: [
- {
- header: "X-Served-From",
- override: false,
- value: "unknown", // This will be overridden by Lambda@Edge
- },
- {
- header: "X-Origin-Domain",
- override: false,
- value: "unknown", // This will be overridden by Lambda@Edge
- },
- {
- header: "X-Stack",
- override: false,
- value: "unknown", // This will be overridden by Lambda@Edge
- },
- ],
- },
- },
-);
-
-// Create WAF Web ACL
-const webAcl = new aws.wafv2.WebAcl(
- `pos-frontend-waf-${stack}`,
- {
- name: `pos-frontend-waf-${stack}`,
- description: "WAF ACL for POS Frontend CloudFront distribution",
- scope: "CLOUDFRONT",
- defaultAction: {
- allow: {},
- },
- rules: [
- // Rate limiting rule - 2000 requests per 5-minute window per IP
- {
- name: "RateLimitRule",
- priority: 1,
- action: {
- block: {
- customResponse: {
- responseCode: 429,
- customResponseBodyKey: "rate_limit_body",
- },
- },
- },
- statement: {
- rateBasedStatement: {
- limit: 3000,
- aggregateKeyType: "IP",
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "RateLimitRule",
- sampledRequestsEnabled: true,
- },
- },
- // AWS Managed Core Rule Set - protection against OWASP Top 10
- {
- name: "AWSManagedRulesCommonRuleSet",
- priority: 2,
- overrideAction: {
- none: {},
- },
- statement: {
- managedRuleGroupStatement: {
- vendorName: "AWS",
- name: "AWSManagedRulesCommonRuleSet",
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "AWSManagedRulesCommonRuleSetMetric",
- sampledRequestsEnabled: true,
- },
- },
- // AWS Managed Known Bad Inputs Rule Set
- {
- name: "AWSManagedRulesKnownBadInputsRuleSet",
- priority: 3,
- overrideAction: {
- none: {},
- },
- statement: {
- managedRuleGroupStatement: {
- vendorName: "AWS",
- name: "AWSManagedRulesKnownBadInputsRuleSet",
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "AWSManagedRulesKnownBadInputsRuleSetMetric",
- sampledRequestsEnabled: true,
- },
- },
- // AWS Managed Amazon IP Reputation List
- {
- name: "AWSManagedRulesAmazonIpReputationList",
- priority: 4,
- overrideAction: {
- none: {},
- },
- statement: {
- managedRuleGroupStatement: {
- vendorName: "AWS",
- name: "AWSManagedRulesAmazonIpReputationList",
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "AWSManagedRulesAmazonIpReputationListMetric",
- sampledRequestsEnabled: true,
- },
- },
- // SQL injection protection
- {
- name: "AWSManagedRulesSQLiRuleSet",
- priority: 5,
- overrideAction: {
- none: {},
- },
- statement: {
- managedRuleGroupStatement: {
- vendorName: "AWS",
- name: "AWSManagedRulesSQLiRuleSet",
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "AWSManagedRulesSQLiRuleSetMetric",
- sampledRequestsEnabled: true,
- },
- },
- // Geographic restriction - Block specific countries if needed
- {
- name: "GeoBlockingRule",
- priority: 6,
- action: {
- block: {},
- },
- statement: {
- geoMatchStatement: {
- // Block countries known for high attack rates - customize as needed
- countryCodes: ["CN", "RU", "KP"], // China, Russia, North Korea
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "GeoBlockingRule",
- sampledRequestsEnabled: true,
- },
- },
- // Size constraint rule - prevent large payloads
- {
- name: "SizeRestrictionRule",
- priority: 7,
- action: {
- block: {},
- },
- statement: {
- orStatement: {
- statements: [
- {
- sizeConstraintStatement: {
- fieldToMatch: {
- body: {
- oversizeHandling: "MATCH",
- },
- },
- comparisonOperator: "GT",
- size: 8192, // 8KB limit for body
- textTransformations: [
- {
- priority: 0,
- type: "NONE",
- },
- ],
- },
- },
- {
- sizeConstraintStatement: {
- fieldToMatch: {
- singleHeader: {
- name: "content-length",
- },
- },
- comparisonOperator: "GT",
- size: 8192,
- textTransformations: [
- {
- priority: 0,
- type: "NONE",
- },
- ],
- },
- },
- ],
- },
- },
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: "SizeRestrictionRule",
- sampledRequestsEnabled: true,
- },
- },
- ],
- customResponseBodies: [
- {
- key: "rate_limit_body",
- content: "Too many requests. Please try again later.",
- contentType: "TEXT_PLAIN",
- },
- ],
- visibilityConfig: {
- cloudwatchMetricsEnabled: true,
- metricName: `pos-frontend-waf-${stack}`,
- sampledRequestsEnabled: true,
- },
- tags: {
- Name: `pos-frontend-waf-${stack}`,
- Environment: stack,
- },
- },
- {
- provider: usEast1Provider, // WAF for CloudFront must be in us-east-1
- },
-);
-
-// Use AWS managed policies to disable caching and forward all viewer headers (except Host)
-const cachingDisabledPolicy = aws.cloudfront
- .getCachePolicyOutput({
- name: "Managed-CachingDisabled",
- })
- .apply((policy) => {
- if (!policy.id) {
- throw new Error("Failed to get caching disabled policy");
- }
- return policy.id;
- });
-const allViewerExceptHostHeaderPolicy = aws.cloudfront
- .getOriginRequestPolicyOutput({
- name: "Managed-AllViewerExceptHostHeader",
- })
- .apply((policy) => {
- if (!policy.id) {
- throw new Error("Failed to get all viewer except host header policy");
- }
- return policy.id;
- });
-
-const certificate = new aws.acm.Certificate(
- `pos-frontend-certificate-${stack}`,
- {
- domainName: config.require("domain"),
- validationMethod: "DNS",
- },
-);
+// Get the qualified ARN (with version) for Lambda@Edge
+const lambdaVersionArn = pulumi.interpolate`${originRouterLambda.arn}:${originRouterLambda.version}`;
const distribution = new aws.cloudfront.Distribution(
`pos-frontend-distribution-${stack}`,
{
- webAclId: webAcl.arn,
defaultCacheBehavior: {
- allowedMethods: ["GET", "HEAD", "OPTIONS"],
+ allowedMethods: [
+ "DELETE",
+ "GET",
+ "HEAD",
+ "OPTIONS",
+ "PATCH",
+ "POST",
+ "PUT",
+ ],
cachedMethods: ["GET", "HEAD"],
compress: true,
// Use default origin as the primary
- targetOriginId: pulumi.interpolate`${branches.find((branch) => branch.name === "STABLE")?.branch.branchName}.${amplify.defaultDomain}`,
+ targetOriginId: pulumi.interpolate`${branches[0].branch.branchName}.${amplify.defaultDomain}`,
viewerProtocolPolicy: "redirect-to-https",
- // Lambda@Edge associations for origin request and response
+ // Lambda@Edge association for origin request
lambdaFunctionAssociations: [
{
eventType: "origin-request",
- lambdaArn: originRouterVersionArn,
- includeBody: false,
- },
- {
- eventType: "origin-response",
- lambdaArn: originResponseVersionArn,
+ lambdaArn: lambdaVersionArn,
includeBody: false,
},
],
- // Disable caching and forward all viewer headers (except Host) using managed policies
- cachePolicyId: cachingDisabledPolicy,
- originRequestPolicyId: allViewerExceptHostHeaderPolicy,
- responseHeadersPolicyId: responseHeadersPolicy.id,
+ // Forward cookies to enable Lambda@Edge to read them
+ forwardedValues: {
+ cookies: {
+ forward: "whitelist",
+ whitelistedNames: [`deployment-${stack}`],
+ },
+ queryString: false,
+ headers: [],
+ },
+ minTtl: 0,
+ defaultTtl: 86400,
+ maxTtl: 31536000,
},
- aliases: [config.require("domain")],
enabled: true,
httpVersion: "http2",
isIpv6Enabled: true,
@@ -776,7 +394,7 @@ const distribution = new aws.cloudfront.Distribution(
customHeaders: [
{
name: "X-Stack-Name",
- value: getCookieStackName(stack),
+ value: stack,
},
{
name: "X-Amplify-Branch-Mappings",
@@ -801,7 +419,7 @@ const distribution = new aws.cloudfront.Distribution(
Name: `pos-frontend-distribution-${stack}`,
},
viewerCertificate: {
- acmCertificateArn: certificate.arn,
+ acmCertificateArn: wildcardCertificate.arn,
sslSupportMethod: "sni-only",
},
},
@@ -814,5 +432,4 @@ export default {
branches,
distribution,
cookieName,
- webAcl,
};
diff --git a/kubb.config.ts b/kubb.config.ts
index 14e3321d..e1c9315d 100644
--- a/kubb.config.ts
+++ b/kubb.config.ts
@@ -109,60 +109,6 @@ export default defineConfig(async () => {
console.error("Failed to fetch spring doc:", error);
}
- // try fetching phoenix config
- try {
- const phoenixDoc = await fetch("http://localhost:8081/swagger/doc.json");
- const phoenixDocJson = await phoenixDoc.json();
-
- configs.push({
- root: ".",
- input: {
- data: phoenixDocJson,
- },
- output: {
- path: "./src/phoenix-generated",
- clean: true,
- },
- hooks: {
- done: ["npx prettier --write ./src/phoenix-generated"],
- },
- plugins: [
- pluginOas({ oasClass: Oas, output: false }),
- createSwaggerTs({
- enumType: "enum",
- }),
- pluginClient({
- client: {
- importPath: "../../config/phoenix-client",
- },
- include: [
- { type: "operationId", pattern: "updateOrderItemDecision" },
- { type: "operationId", pattern: "createWebsocketConnection" },
- { type: "operationId", pattern: "removeWebsocketConnection" },
- { type: "operationId", pattern: "getTransactionByTransactionItem" },
- ],
- }),
- pluginTanstackQuery({
- framework: "react",
- infinite: false,
- client: {
- importPath: "../../config/phoenix-client",
- },
- output: {
- path: "./hooks",
- },
- mutate: {
- variablesType: "mutate",
- methods: ["post", "put", "delete", "patch"],
- },
- templates,
- }),
- ],
- });
- } catch (error) {
- console.error("Failed to fetch phoenix doc:", error);
- }
-
// Always add the POSServiceModel config
configs.push({
root: ".",
diff --git a/lambda-edge/origin-response.js b/lambda-edge/origin-response.js
deleted file mode 100644
index 7876a57e..00000000
--- a/lambda-edge/origin-response.js
+++ /dev/null
@@ -1,80 +0,0 @@
-"use strict";
-
-exports.handler = async (event, ctx, callback) => {
- const request = event.Records[0].cf.request;
- const response = event.Records[0].cf.response;
-
- try {
- // Extract the origin domain that was actually used
- const originDomain =
- request.origin && request.origin.custom
- ? request.origin.custom.domainName
- : "unknown";
-
- // Extract stack name from custom headers (passed from CloudFront origin config)
- let stack = "prod"; // default value
- let branchMappings = {};
-
- if (
- request.origin &&
- request.origin.custom &&
- request.origin.custom.customHeaders
- ) {
- const stackHeader = request.origin.custom.customHeaders["x-stack-name"];
- if (stackHeader && stackHeader[0]) {
- stack = stackHeader[0].value;
- }
-
- const branchMappingsHeader =
- request.origin.custom.customHeaders["x-amplify-branch-mappings"];
- if (branchMappingsHeader && branchMappingsHeader[0]) {
- branchMappings = JSON.parse(branchMappingsHeader[0].value);
- }
- }
-
- console.log(`Origin domain served: ${originDomain}`);
- console.log(`Stack: ${stack}`);
- console.log(`Branch mappings:`, branchMappings);
-
- // Determine which deployment target was served by matching the origin domain
- let deploymentTarget = "UNKNOWN";
- for (const [target, domain] of Object.entries(branchMappings)) {
- if (domain === originDomain) {
- deploymentTarget = target;
- break;
- }
- }
-
- // Add response headers to indicate which deployment was served
- response.headers["x-served-from"] = [
- {
- key: "X-Served-From",
- value: deploymentTarget,
- },
- ];
-
- response.headers["x-origin-domain"] = [
- {
- key: "X-Origin-Domain",
- value: originDomain,
- },
- ];
-
- response.headers["x-stack"] = [
- {
- key: "X-Stack",
- value: stack,
- },
- ];
-
- console.log(
- `Added response headers: X-Served-From=${deploymentTarget}, X-Origin-Domain=${originDomain}, X-Stack=${stack}`,
- );
-
- callback(null, response);
- } catch (error) {
- console.error("Error in origin-response Lambda:", error);
- // Continue with original response even if our logic fails
- callback(null, response);
- }
-};
diff --git a/lambda-edge/origin-router.js b/lambda-edge/origin-router.js
index cb4a3dbb..a8c67de6 100644
--- a/lambda-edge/origin-router.js
+++ b/lambda-edge/origin-router.js
@@ -1,74 +1,63 @@
"use strict";
-exports.handler = async (event, ctx, callback) => {
+exports.handler = async (event) => {
const request = event.Records[0].cf.request;
- try {
- const headers = request.headers;
+ const headers = request.headers;
- // Extract stack name from custom headers passed by CloudFront
- let stack = "prod"; // default value
- let branchMappings = {};
- if (
- request.origin &&
- request.origin.custom &&
- request.origin.custom.customHeaders
- ) {
- const stackHeader = request.origin.custom.customHeaders["x-stack-name"];
- if (stackHeader && stackHeader[0]) {
- stack = stackHeader[0].value;
- }
- const branchMappingsHeader =
- request.origin.custom.customHeaders["x-amplify-branch-mappings"];
- if (branchMappingsHeader && branchMappingsHeader[0]) {
- branchMappings = JSON.parse(branchMappingsHeader[0].value);
- }
- if (Object.keys(branchMappings).length === 0) {
- throw new Error("Branch mappings are required");
- }
+ // Extract stack name from custom headers passed by CloudFront
+ let stack = "prod"; // default value
+ let branchMappings = {};
+ if (
+ request.origin &&
+ request.origin.custom &&
+ request.origin.custom.customHeaders
+ ) {
+ const stackHeader = request.origin.custom.customHeaders["x-stack-name"];
+ if (stackHeader && stackHeader[0]) {
+ stack = stackHeader[0].value;
}
+ const branchMappingsHeader =
+ request.origin.custom.customHeaders["x-amplify-branch-mappings"];
+ if (branchMappingsHeader && branchMappingsHeader[0]) {
+ branchMappings = JSON.parse(branchMappingsHeader[0].value);
+ }
+ if (Object.keys(branchMappings).length === 0) {
+ throw new Error("Branch mappings are required");
+ }
+ }
- const cookieName = `deployment-${stack}`;
-
- // Parse cookies from the request
- const cookies = parseCookies(headers.cookie || []);
- const deploymentCookie = cookies[cookieName];
+ const cookieName = `deployment-${stack}`;
- console.log(
- `Stack: ${stack}, Cookie ${cookieName} value: ${deploymentCookie}`,
- );
+ // Parse cookies from the request
+ const cookies = parseCookies(headers.cookie || []);
+ const deploymentCookie = cookies[cookieName];
- console.log(request.origin);
+ console.log(
+ `Stack: ${stack}, Cookie ${cookieName} value: ${deploymentCookie}`,
+ );
- // Map cookie values to origin domains
- // Cookie values should be: "STABLE", "CANARY"
- if (deploymentCookie) {
- const targetBranch = branchMappings[deploymentCookie];
+ // Map cookie values to origin domains
+ // Cookie values should be: "PROD", "BETA", or "GAMMA" (matching the branch names)
+ if (deploymentCookie) {
+ const targetBranch = branchMappings[deploymentCookie];
- if (targetBranch) {
- request.origin.custom.domainName = targetBranch;
- request.headers.host = [{ key: "host", value: targetBranch }];
- console.log(`Routing to custom origin: ${targetBranch}`);
- } else {
- console.log(
- `Invalid cookie value: ${deploymentCookie}, using default origin`,
- );
- request.origin.custom.domainName = branchMappings["STABLE"];
- request.headers.host = [
- { key: "host", value: branchMappings["STABLE"] },
- ];
- console.log(`Routing to custom origin: ${branchMappings["STABLE"]}`);
- }
+ if (targetBranch) {
+ request.origin.custom.domainName = targetBranch;
+ request.headers.host = [{ key: "Host", value: targetBranch }];
+ console.log(`Routing to custom origin: ${targetBranch}`);
} else {
- console.log(`No ${cookieName} cookie found, using default origin`);
+ console.log(
+ `Invalid cookie value: ${deploymentCookie}, using default origin`,
+ );
+ request.origin.custom.domainName = branchMappings["STABLE"];
+ request.headers.host = [{ key: "Host", value: branchMappings["STABLE"] }];
+ console.log(`Routing to custom origin: ${branchMappings["STABLE"]}`);
}
-
- console.log(request.headers);
-
- callback(null, request);
- } catch (error) {
- console.error(error);
- callback(null, request);
+ } else {
+ console.log(`No ${cookieName} cookie found, using default origin`);
}
+
+ return request;
};
function parseCookies(cookieHeaders) {
diff --git a/package.json b/package.json
index 0e944991..b5b7fe09 100644
--- a/package.json
+++ b/package.json
@@ -7,11 +7,6 @@
"@chakra-ui/icons": "^2.0.19",
"@chakra-ui/react": "^2.10.7",
"@chakra-ui/theme": "^3.4.6",
- "@electric-sql/pglite": "^0.3.9",
- "@electric-sql/pglite-react": "^0.2.27",
- "@electric-sql/pglite-sync": "^0.3.13",
- "@electric-sql/pglite-tools": "^0.2.14",
- "@electric-sql/react": "^1.0.10",
"@emotion/babel-plugin": "^11.11.0",
"@emotion/react": "^11.11.1",
"@faker-js/faker": "^8.4.1",
@@ -49,9 +44,6 @@
"@remixicon/react": "^4.2.0",
"@sentry/cli": "^2.35.0",
"@sentry/react": "^7.113.0",
- "@statsig/react-bindings": "^3.25.3",
- "@statsig/session-replay": "^3.25.3",
- "@statsig/web-analytics": "^3.25.3",
"@stripe/connect-js": "^3.3.0",
"@stripe/react-connect-js": "^3.3.2",
"@stripe/react-stripe-js": "^2.7.0",
@@ -114,7 +106,7 @@
"react-slot-counter": "^2.3.3",
"react-textarea-autosize": "^8.5.6",
"react-thermal-printer": "^0.21.0",
- "react-use-websocket": "^4.13.0",
+ "react-use-websocket": "^4.8.1",
"recharts": "^2.15.2",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
@@ -151,7 +143,7 @@
"test-storybook": "test-storybook"
},
"lint-staged": {
- "**/*": "prettier --write --experimental-cli --ignore-unknown"
+ "**/*": "prettier --write --ignore-unknown"
},
"browserslist": {
"production": [
@@ -182,7 +174,6 @@
"@kubb/swagger-tanstack-query": "^2.28.4",
"@kubb/swagger-ts": "^2.28.4",
"@mixer/parallel-prettier": "^2.0.3",
- "@prettier/plugin-oxc": "^0.0.4",
"@pulumi/aws": "^7.0.0",
"@pulumi/awsx": "^3.0.0",
"@pulumi/pulumi": "^3.113.0",
@@ -221,20 +212,21 @@
"http-server": "^14.1.1",
"husky": "^8.0.3",
"jsdom": "^24.1.0",
- "lint-staged": "^15.5.2",
+ "lint-staged": "^13.2.3",
"msw": "2.8.4",
"msw-storybook-addon": "2.0.3",
"postcss": "^8.4.35",
"prettier": "^3.6.0",
- "prettier-plugin-organize-imports": "^4.3.0",
+ "prettier-plugin-organize-imports": "^3.2.4",
"prop-types": "^15.8.1",
"storybook": "^8.1.0",
"tailwindcss": "^3.4.1",
+ "tempo-devtools": "^2.0.80",
"ts-jest": "^29.1.4",
"tsx": "^4.20.5",
"vite-plugin-checker": "^0.6.4",
"vite-plugin-eslint": "^1.8.1",
- "vite-plugin-pwa": "^1.0.3",
+ "vite-plugin-pwa": "^0.20.5",
"vitest": "^3.1.4",
"wait-on": "^7.2.0",
"webpack": "^5.89.0",
diff --git a/public/sounds/notification.wav b/public/sounds/notification.wav
deleted file mode 100644
index 88a18e15..00000000
Binary files a/public/sounds/notification.wav and /dev/null differ
diff --git a/public/version.json b/public/version.json
index cbeadc3e..1c252cf4 100644
--- a/public/version.json
+++ b/public/version.json
@@ -1,3 +1,3 @@
{
- "version": "8091c4ddafsfasa2272c590d0e508dc3db0c777"
+ "version": "8091jjjjjjjjjjj2272c590d0e508dc3db0c777"
}
diff --git a/src/App.tsx b/src/App.tsx
index 1ffd3820..2e1846dd 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,18 +11,18 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { FocusDialog } from "components/FocusDialog";
import { LabelPrintProvider } from "components/label/LabelPrinterContext";
-import PGliteProvider from "components/pg-lite/PGliteProvider";
import { SalePageConfigProvider } from "components/SalesScreenComponents/SalePageConfigProvider";
import { SentryErrorBoundary } from "config/sentry/SentryErrorBoundary";
import { AppVersionProvider } from "context/AppVersionContext";
import { DepartmentProvider } from "context/DepartmentContext";
import { ReactNode, Suspense, useEffect, useMemo, useState } from "react";
import {
- createBrowserRouter,
Outlet,
RouterProvider,
+ createBrowserRouter,
useLocation,
} from "react-router-dom";
+import routes from "tempo-routes";
import { QueryParamProvider } from "use-query-params";
import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
import { PermissionRequiredRoute } from "./components/Auth/PermissionRequiredRoute";
@@ -47,9 +47,6 @@ const PromotionsDashboard = lazy(
() => import("./pages/promotions/PromotionsDashboard"),
);
const SettingsPage = lazy(() => import("./pages/Settings/SettingsPage"));
-const EditSalesChannelPage = lazy(
- () => import("./pages/Settings/SalesChannels/EditSalesChannelPage"),
-);
const TotalsReport = lazy(
() => import("./pages/report/TotalsReport/TotalsReportPage"),
);
@@ -207,13 +204,15 @@ const GlobalProvider = ({ children }: { children: ReactNode }) => {
}, [location.pathname]);
return (
- <AuthorizationContextProvider>
- <SearchProvider>
- <QueryParamProvider adapter={ReactRouter6Adapter}>
- <AppVersionProvider>{children}</AppVersionProvider>
- </QueryParamProvider>
- </SearchProvider>
- </AuthorizationContextProvider>
+ <>
+ <AuthorizationContextProvider>
+ <SearchProvider>
+ <QueryParamProvider adapter={ReactRouter6Adapter}>
+ <AppVersionProvider>{children}</AppVersionProvider>
+ </QueryParamProvider>
+ </SearchProvider>
+ </AuthorizationContextProvider>
+ </>
);
};
@@ -555,15 +554,13 @@ const router = createBrowserRouter([
element: (
<DepartmentProvider>
<SalePageConfigProvider>
- <PGliteProvider>
- <SalesContextProvider>
- <FocusDialog>
- <RequiresDrawerSettlement>
- <SalePage />
- </RequiresDrawerSettlement>
- </FocusDialog>
- </SalesContextProvider>
- </PGliteProvider>
+ <SalesContextProvider>
+ <FocusDialog>
+ <RequiresDrawerSettlement>
+ <SalePage />
+ </RequiresDrawerSettlement>
+ </FocusDialog>
+ </SalesContextProvider>
</SalePageConfigProvider>
</DepartmentProvider>
),
@@ -933,20 +930,6 @@ const router = createBrowserRouter([
crumb: () => "Inventory Transfers",
},
},
- {
- path: "/settings/sales-channels/:id/edit",
- element: (
- <DepartmentProvider>
- <PermissionRequiredRoute
- element={EditSalesChannelPage}
- permission="saleschannel/*:manage"
- />
- </DepartmentProvider>
- ),
- handle: {
- crumb: () => "Edit Sales Channel",
- },
- },
{
path: "/settings/*",
element: (
@@ -1018,6 +1001,7 @@ const router = createBrowserRouter([
path: "*",
element: <NotFoundPage />,
},
+ ...(import.meta.env.VITE_TEMPO ? routes : []),
]);
export const App = () => {
diff --git a/src/codegen/kubb/templates/templates.tsx b/src/codegen/kubb/templates/templates.tsx
index 41d4333a..9abc74eb 100644
--- a/src/codegen/kubb/templates/templates.tsx
+++ b/src/codegen/kubb/templates/templates.tsx
@@ -35,7 +35,6 @@ export const templates = {
const clientOptions = [
`method: "${client.method}"`,
`url: ${client.path.template}`,
- `signal: signal`,
client.withQueryParams && !infinite ? "params" : undefined,
client.withData && !isFormData ? "data" : undefined,
client.withData && isFormData ? "data: formData" : undefined,
@@ -107,7 +106,7 @@ export const templates = {
return infiniteQueryOptions({
queryKey,
- queryFn: async ({ pageParam, signal }) => {
+ queryFn: async ({ pageParam }) => {
${hook.children || ""}
${formData || ""}
const res = await client<${client.generics}>({
@@ -138,7 +137,7 @@ export const templates = {
return {
queryKey,
- queryFn: async ({ pageParam, signal }) => {
+ queryFn: async ({ pageParam }) => {
${hook.children || ""}
${formData || ""}
const res = await client<${client.generics}>({
@@ -163,7 +162,7 @@ export const templates = {
return queryOptions({
queryKey,
- queryFn: async ({signal}) => {
+ queryFn: async () => {
${hook.children || ""}
${formData || ""}
const res = await client<${client.generics}>({
@@ -194,7 +193,7 @@ export const templates = {
return {
queryKey,
- queryFn: async ({signal}) => {
+ queryFn: async () => {
${hook.children || ""}
${formData || ""}
const res = await client<${client.generics}>({
diff --git a/src/components/CreateItem/ConfirmCreateItemDialog.tsx b/src/components/CreateItem/ConfirmCreateItemDialog.tsx
index 6241e8f1..f1caaadb 100644
--- a/src/components/CreateItem/ConfirmCreateItemDialog.tsx
+++ b/src/components/CreateItem/ConfirmCreateItemDialog.tsx
@@ -89,6 +89,12 @@ export const ConfirmCreateItemDialog = ({
warnings.push("The item is not being created for all stores.");
}
+ if (values.parentCohortItem && parentItem?.packSize === 1) {
+ warnings.push(
+ "The parent item is a single pack item. Having a child of a single will likely cause inventory issues.",
+ );
+ }
+
if (changedPriceFields.length > 0) {
warnings.push(
`The mentioned pricing fields are not same across all the entities: ${changedPriceFields.join(", ")}.`,
@@ -96,7 +102,6 @@ export const ConfirmCreateItemDialog = ({
}
return warnings;
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
itemName,
values.bottleFeeMultiplier,
diff --git a/src/components/DatabaseSyncLoader.tsx b/src/components/DatabaseSyncLoader.tsx
deleted file mode 100644
index 6235d50d..00000000
--- a/src/components/DatabaseSyncLoader.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useEffect, useState } from "react";
-import { cn } from "../lib/utils";
-
-interface DatabaseSyncLoaderProps {
- message?: string;
- showProgress?: boolean;
- className?: string;
-}
-
-export function DatabaseSyncLoader({
- message = "Syncing database...",
- showProgress = false,
- className,
-}: DatabaseSyncLoaderProps) {
- const [progress, setProgress] = useState(0);
- const [dots, setDots] = useState("");
-
- // Animate the progress bar if showProgress is true
- useEffect(() => {
- if (!showProgress) return;
-
- const interval = setInterval(() => {
- setProgress((prev) => {
- return Math.min(prev + Math.random() * 10, 90);
- });
- }, 2500);
-
- return () => clearInterval(interval);
- }, [showProgress]);
-
- // Animate the dots in the loading text
- useEffect(() => {
- const interval = setInterval(() => {
- setDots((prev) => {
- if (prev === "...") return "";
- return `${prev}.`;
- });
- }, 500);
-
- return () => clearInterval(interval);
- }, []);
-
- return (
- <div
- className={cn(
- "flex flex-col items-center justify-center p-8 space-y-6",
- "bg-card border border-border rounded-lg shadow-sm",
- "min-h-[200px] w-full max-w-md mx-auto",
- className,
- )}
- >
- {/* Animated Spinner */}
- <div className="relative">
- <div className="w-12 h-12 border-4 border-muted rounded-full animate-spin border-t-primary" />
- </div>
-
- {/* Loading Text */}
- <div className="text-center space-y-2">
- <h3 className="text-lg font-semibold text-foreground">
- {message}
- {dots}
- </h3>
- <p className="text-sm text-muted-foreground">
- Please wait while we prepare your data
- </p>
- </div>
-
- {/* Progress Bar (optional) */}
- {showProgress && (
- <div className="w-full space-y-2">
- <div className="flex justify-between text-xs text-muted-foreground">
- <span>Syncing</span>
- <span>{Math.round(progress)}%</span>
- </div>
- <div className="w-full bg-secondary rounded-full h-2 overflow-hidden">
- <div
- className="h-full bg-primary rounded-full transition-all duration-500 ease-out"
- style={{ width: `${progress}%` }}
- />
- </div>
- </div>
- )}
-
- {/* Database Icon */}
- <div className="flex items-center space-x-2 text-xs text-muted-foreground">
- <svg
- className="w-4 h-4"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <title>Database Icon</title>
- <ellipse cx="12" cy="5" rx="9" ry="3" />
- <path d="M3 5v14c0 1.66 4.03 3 9 3s9-1.34 9-3V5" />
- <path d="M3 12c0 1.66 4.03 3 9 3s9-1.34 9-3" />
- </svg>
- <span>Transformity Database</span>
- </div>
- </div>
- );
-}
diff --git a/src/components/Employee/EmployeeTimeTable.tsx b/src/components/Employee/EmployeeTimeTable.tsx
index 3a31b235..8828e5be 100644
--- a/src/components/Employee/EmployeeTimeTable.tsx
+++ b/src/components/Employee/EmployeeTimeTable.tsx
@@ -253,7 +253,6 @@ export const EmployeeTimeTable = ({
]
: []),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[handleUpdateTime, handleOnSave, isUpdatingTimePunch],
);
diff --git a/src/components/EntityAssetUpload.tsx b/src/components/EntityAssetUpload.tsx
index 3ddada01..5c0306f3 100644
--- a/src/components/EntityAssetUpload.tsx
+++ b/src/components/EntityAssetUpload.tsx
@@ -74,7 +74,6 @@ export function EntityAssetUpload({
.then((result) => {
setCurrentAssetUrl(result);
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [entity.id, entityConfig]);
const handleValidationError = useCallback(
diff --git a/src/components/ItemDetailComponents/AddtoListDialog.tsx b/src/components/ItemDetailComponents/AddtoListDialog.tsx
index ba20d092..b43e9450 100644
--- a/src/components/ItemDetailComponents/AddtoListDialog.tsx
+++ b/src/components/ItemDetailComponents/AddtoListDialog.tsx
@@ -56,11 +56,9 @@ export const AddToListDialog = ({ cohortItemId }: AddToListDialogProps) => {
resolver: zodResolver(AddToListSchema),
});
- const reset = form.reset;
-
useEffect(() => {
- reset({});
- }, [cohortItemId, reset]);
+ form.reset({});
+ }, [cohortItemId]);
const { mutateAsync: createItemListItem, isPending } = usePostItemListItem(
form.getValues().selectedListOption?.value,
diff --git a/src/components/ItemDetailComponents/EditableItemTable/EditableItemRow2.tsx b/src/components/ItemDetailComponents/EditableItemTable/EditableItemRow2.tsx
index fc2dfc56..0a96d356 100644
--- a/src/components/ItemDetailComponents/EditableItemTable/EditableItemRow2.tsx
+++ b/src/components/ItemDetailComponents/EditableItemTable/EditableItemRow2.tsx
@@ -629,7 +629,6 @@ export const EditableItemRow2: React.FC<EditableItemRow2Props> = ({
];
},
// Disabling because we want to use ID as a dependency
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
allPossibleEntities,
nonInventory,
diff --git a/src/components/ItemListsComponents/ItemListDetailPageFooter.tsx b/src/components/ItemListsComponents/ItemListDetailPageFooter.tsx
index 6d1a4677..9f17f696 100644
--- a/src/components/ItemListsComponents/ItemListDetailPageFooter.tsx
+++ b/src/components/ItemListsComponents/ItemListDetailPageFooter.tsx
@@ -103,7 +103,6 @@ export const ItemListDetailPageFooter = ({
void debouncedChangeHandler(itemFilters);
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[popoverOpen, entity.id, debouncedChangeHandler, itemFilters],
);
diff --git a/src/components/ItemListsComponents/ItemListsFilters.tsx b/src/components/ItemListsComponents/ItemListsFilters.tsx
index cdb76601..bd45d239 100644
--- a/src/components/ItemListsComponents/ItemListsFilters.tsx
+++ b/src/components/ItemListsComponents/ItemListsFilters.tsx
@@ -28,7 +28,6 @@ export const ItemListsFilters = ({
if (!searchValue && name) {
setSearchValue(name);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [name]);
return (
diff --git a/src/components/ItemSearchComponents/ItemSearchBoxV2.tsx b/src/components/ItemSearchComponents/ItemSearchBoxV2.tsx
index baf8226e..8b7c6e64 100644
--- a/src/components/ItemSearchComponents/ItemSearchBoxV2.tsx
+++ b/src/components/ItemSearchComponents/ItemSearchBoxV2.tsx
@@ -24,7 +24,7 @@ export type ItemSearchBoxV2Value = {
export type ItemSearchBoxV2Props = {
placeholder?: string;
- onSearchSelected?: (item?: EntityItemDetail) => void | Promise<void>;
+ onSearchSelected?: (item?: EntityItemDetail) => void;
value?: ItemSearchBoxV2Value;
className?: string;
isDisabled?: boolean;
@@ -156,11 +156,9 @@ export const ItemSearchBoxV2 = forwardRef<
const itemByIdOptions = getItemByIdQueryOptions(
selectedItem?.id ?? -1,
);
- void queryClient
- .fetchQuery(itemByIdOptions)
- .then(async (response) => {
- await onSearchSelected(response);
- });
+ void queryClient.fetchQuery(itemByIdOptions).then((response) => {
+ onSearchSelected(response);
+ });
}}
onSearch={debouncedSearch}
placeholder={placeholder}
diff --git a/src/components/MultiplePayments.tsx b/src/components/MultiplePayments.tsx
index 555e582a..2de9021b 100644
--- a/src/components/MultiplePayments.tsx
+++ b/src/components/MultiplePayments.tsx
@@ -58,7 +58,6 @@ import {
} from "./payment/disablePaymentMethods";
import { CancelPayinButton } from "./SalesScreenComponents/Modals/CancelPayinButton";
import { PayWithHouseAccount } from "./SalesScreenComponents/Modals/payments/PayWithHouseAccount";
-import { PriceLevelHelper } from "./SalesScreenComponents/Modals/PriceLevelHelper";
import { Button, ButtonProps } from "./ui/button";
import { Separator } from "./ui/separator";
import { Slider } from "./ui/slider";
@@ -372,11 +371,6 @@ const MultiplePayments = ({
</HStack>
<Divider />
</VStack>
-
- {/* Price Level Helper */}
- <PriceLevelHelper transactionTotal={transactionTotalPrice} />
- <Divider />
-
<FormControl>
<FormLabel>Cash Amount:</FormLabel>
<MultiplePaymentsInput
@@ -637,7 +631,6 @@ const MultiplePayments = ({
}}
/>
<Button
- type="button"
tabIndex={-1}
disabled={!customer?.points}
onFocus={(e) => e.currentTarget.blur()}
@@ -702,22 +695,12 @@ const MultiplePayments = ({
setHouseAccountAmount={(houseAccountAmount) => {
dispatch({
moneyType: MoneyType.HOUSE_ACCOUNT,
- amount: +houseAccountAmount,
+ amount: houseAccountAmount,
});
}}
houseAccountId={moneyState.houseAccountId ?? ""}
amount={moneyState.houseAccountAmount ?? 0}
- maxAmount={
- transactionTotalPrice -
- moneyState.cash -
- moneyState.creditCard -
- moneyState.creditCard2 -
- moneyState.creditCard3 -
- moneyState.check -
- moneyState.giftCard -
- moneyState.pointsDollars -
- moneyState.other
- }
+ maxAmount={transactionTotalPrice}
/>
) : (
<FormHelperText>No customer selected</FormHelperText>
diff --git a/src/components/NewItem.tsx b/src/components/NewItem.tsx
index 3ba5b414..ce5559b1 100644
--- a/src/components/NewItem.tsx
+++ b/src/components/NewItem.tsx
@@ -49,9 +49,7 @@ const NewItem = ({ onSubmit, giftCardDisclosure }: NewItemProps) => {
setPrice(1);
setBottleFeeMulti(0);
setEnvFeeMulti(0);
- setSelectedDepartment(
- departments.get("Misc") || departments.values().next().value,
- );
+ setSelectedDepartment(departments.get("Misc"));
},
});
diff --git a/src/components/PoleDisplay.tsx b/src/components/PoleDisplay.tsx
new file mode 100644
index 00000000..460eeab8
--- /dev/null
+++ b/src/components/PoleDisplay.tsx
@@ -0,0 +1,91 @@
+import * as Sentry from "config/sentry/TransformitySentry";
+import { useCallback, useState } from "react";
+import { useEffectOnce } from "usehooks-ts";
+
+const BAUD_RATE = 9600;
+const encoder = new TextEncoder();
+const USB_VENDOR_ID = 4008;
+
+export const useRequestPoleDisplay = () => {
+ const requestPoleDisplay = useCallback(async () => {
+ if (!navigator.serial) {
+ return;
+ }
+ try {
+ return await navigator.serial.requestPort({
+ // chrome://device-log
+ filters: [{ usbVendorId: USB_VENDOR_ID }],
+ });
+ } catch (e) {
+ if (e instanceof DOMException) {
+ if (e.name === "NotFoundError") {
+ // User cancelled the request
+ console.warn(e);
+ return;
+ }
+ }
+ Sentry.captureException(e);
+ }
+ }, []);
+ return requestPoleDisplay;
+};
+
+const usePoleDisplay = () => {
+ const [device, setDevice] = useState<SerialPort>();
+
+ useEffectOnce(() => {
+ if (navigator.serial) {
+ navigator.serial
+ .getPorts()
+ .then((devicesT) => {
+ const deviceT = devicesT.find(
+ (deviceT) => deviceT.getInfo().usbVendorId === USB_VENDOR_ID,
+ );
+ setDevice(deviceT);
+ })
+ .catch((err) => {
+ Sentry.captureException(err);
+ });
+ }
+ });
+
+ const sendData = useCallback(
+ async (display1: string, display2: string) => {
+ if (!device) return;
+
+ try {
+ await device.open({ baudRate: BAUD_RATE });
+ } catch (e) {
+ if (e instanceof DOMException) {
+ if (["InvalidStateError", "NotFoundError"].includes(e.name)) {
+ // The device is already open
+ console.warn(e);
+ return;
+ }
+ }
+ Sentry.captureException(e);
+ return;
+ }
+ const writer = device.writable.getWriter();
+
+ void writer.write(encoder.encode(String.fromCharCode(31))); // Clear
+ void writer.write(encoder.encode(String.fromCharCode(17))); // Welcome Message
+ void writer.write(
+ encoder.encode(
+ display1 + " ".substring(0, 20 - display1.length),
+ ),
+ );
+ void writer.write(
+ encoder.encode(
+ display2 + " ".substring(0, 19 - display2.length),
+ ),
+ );
+ await writer.close();
+ await device.close();
+ },
+ [device],
+ );
+
+ return sendData;
+};
+export default usePoleDisplay;
diff --git a/src/components/PriceLevelSelect.tsx b/src/components/PriceLevelSelect.tsx
index 5fbdf954..6261bc61 100644
--- a/src/components/PriceLevelSelect.tsx
+++ b/src/components/PriceLevelSelect.tsx
@@ -8,13 +8,11 @@ import { ComboboxSelect } from "./ui/ComboboxSelect";
export type PriceLevelSelectProps = {
value: string | undefined;
- salesChannelId?: number | undefined;
onChange: (val: string) => void;
};
export const PriceLevelSelect: React.FC<PriceLevelSelectProps> = ({
value,
- salesChannelId,
onChange,
}) => {
const [entity] = useEntitySelected();
@@ -27,7 +25,6 @@ export const PriceLevelSelect: React.FC<PriceLevelSelectProps> = ({
useExecuteSearchCohortpriceleveldbGet({
cohortId: entity?.cohortId,
size: 30,
- salesChannelId: salesChannelId,
name: priceLevelSearch,
});
@@ -36,7 +33,6 @@ export const PriceLevelSelect: React.FC<PriceLevelSelectProps> = ({
(pl) => pl.id === Number(value),
);
setSelectedPriceLevel(pl);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [priceLevels]);
const priceLevelOptions = useMemo(
diff --git a/src/components/ReceiptPrinter.tsx b/src/components/ReceiptPrinter.tsx
index a6b25261..a762961a 100644
--- a/src/components/ReceiptPrinter.tsx
+++ b/src/components/ReceiptPrinter.tsx
@@ -79,7 +79,6 @@ export const useReceiptPrinter: () => [
console.error(e);
captureException(e);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const sendDataV2 = useCallback(async (elements: JSX.Element) => {
diff --git a/src/components/SalePageSyncOverlay.tsx b/src/components/SalePageSyncOverlay.tsx
deleted file mode 100644
index 41447c3e..00000000
--- a/src/components/SalePageSyncOverlay.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { DatabaseSyncLoader } from "./DatabaseSyncLoader";
-import { usePGliteSync } from "./pg-lite/PGliteSyncContext";
-
-interface SalePageSyncOverlayProps {
- children: React.ReactNode;
-}
-
-export const SalePageSyncOverlay: React.FC<SalePageSyncOverlayProps> = ({
- children,
-}) => {
- const { isSyncing } = usePGliteSync();
-
- if (isSyncing) {
- return (
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-background/95 backdrop-blur-sm">
- <div className="text-center space-y-4">
- <DatabaseSyncLoader
- message="Syncing POS database"
- showProgress={true}
- className="shadow-lg"
- />
- <div className="text-sm text-muted-foreground max-w-md">
- <p>We're preparing your point-of-sale system.</p>
- <p>This usually takes just a few moments...</p>
- </div>
- </div>
- </div>
- );
- }
-
- return <>{children}</>;
-};
diff --git a/src/components/SalesChannels/ArchivedPaymentMethodsModal.tsx b/src/components/SalesChannels/ArchivedPaymentMethodsModal.tsx
deleted file mode 100644
index ecbbece6..00000000
--- a/src/components/SalesChannels/ArchivedPaymentMethodsModal.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-import { Button } from "components/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from "components/ui/dialog";
-import { LoadingSpinner } from "components/ui/loading-spinner";
-import { useEntitySelected } from "context/EntityProvider";
-import { Archive, RotateCcw } from "lucide-react";
-import React, { useState } from "react";
-import { toast } from "sonner";
-import {
- EntitySalesChannelPaymentMethod,
- useSearchEntitySalesChannelPaymentMethods,
- useUpdateEntitySalesChannelPaymentMethod,
-} from "src/spring-generated";
-
-interface ArchivedPaymentMethodsModalProps {
- isOpen: boolean;
- onClose: () => void;
- salesChannelId: number;
- onPaymentMethodUnarchived?: () => Promise<void>;
-}
-
-export const ArchivedPaymentMethodsModal: React.FC<
- ArchivedPaymentMethodsModalProps
-> = ({ isOpen, onClose, salesChannelId, onPaymentMethodUnarchived }) => {
- const [entity] = useEntitySelected();
- const [unarchivingIds] = useState<Set<string>>(new Set());
-
- // Fetch archived payment methods
- const {
- data: archivedPaymentMethods,
- isLoading,
- refetch,
- isFetching,
- } = useSearchEntitySalesChannelPaymentMethods(
- {
- entitySalesChannelId: salesChannelId,
- entityId: entity?.id || 0,
- isArchived: true,
- page: 0,
- size: 100,
- },
- {
- query: {
- enabled: isOpen && !!salesChannelId && !!entity?.id,
- queryKey: ["archived-payment-methods", salesChannelId, entity?.id],
- },
- },
- );
-
- const { mutateAsync: updatePaymentMethod } =
- useUpdateEntitySalesChannelPaymentMethod();
-
- const handleUnarchive = async (
- paymentMethod: EntitySalesChannelPaymentMethod,
- ) => {
- if (!paymentMethod.id) return;
-
- try {
- await updatePaymentMethod({
- data: {
- id: paymentMethod.id,
- entityId: entity?.id || 0,
- entitySalesChannelId: salesChannelId,
- paymentMethodType: paymentMethod.paymentMethodType,
- cohortPriceLevelId: paymentMethod.cohortPriceLevelId,
- displayOnPayButton: paymentMethod.displayOnPayButton,
- isArchived: false,
- },
- });
-
- toast.success("Payment method unarchived successfully");
- void refetch();
- await onPaymentMethodUnarchived?.();
- } catch (error) {
- toast.error("Failed to unarchive payment method");
- console.error("Error unarchiving payment method:", error);
- }
- };
-
- const formatPaymentMethodName = (type: string) => {
- return type
- .split("_")
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
- .join(" ");
- };
-
- return (
- <Dialog open={isOpen} onOpenChange={onClose}>
- <DialogContent className="max-w-2xl">
- <DialogHeader>
- <DialogTitle className="flex items-center gap-2">
- <Archive className="h-5 w-5" />
- Archived Payment Methods
- </DialogTitle>
- <DialogDescription>
- View and restore archived payment methods for this sales channel.
- </DialogDescription>
- </DialogHeader>
-
- <div className="mt-4">
- {isLoading || isFetching ? (
- <div className="flex items-center justify-center py-8">
- <LoadingSpinner />
- </div>
- ) : archivedPaymentMethods?.content?.length === 0 ? (
- <div className="text-center py-8 text-gray-500">
- <Archive className="h-12 w-12 mx-auto mb-4 text-gray-300" />
- <p className="text-lg font-medium">No archived payment methods</p>
- <p className="text-sm">
- All payment methods for this sales channel are currently active.
- </p>
- </div>
- ) : (
- <div className="space-y-3">
- {archivedPaymentMethods?.content?.map((paymentMethod) => (
- <div
- key={paymentMethod.id}
- className="flex items-center justify-between p-4 border rounded-lg bg-gray-50"
- >
- <div className="flex-1">
- <div className="flex items-center gap-3">
- <div>
- <p className="font-medium text-gray-900">
- {formatPaymentMethodName(
- paymentMethod.paymentMethodType,
- )}
- </p>
- <p className="text-sm text-gray-500">
- ID: {paymentMethod.id}
- </p>
- </div>
- </div>
- </div>
- <Button
- onClick={() => handleUnarchive(paymentMethod)}
- disabled={unarchivingIds.has(paymentMethod.id)}
- size="sm"
- variant="outline"
- className="flex items-center gap-2"
- >
- {unarchivingIds.has(paymentMethod.id) ? (
- <LoadingSpinner className="h-3 w-3" />
- ) : (
- <RotateCcw className="h-3 w-3" />
- )}
- Unarchive
- </Button>
- </div>
- ))}
- </div>
- )}
- </div>
-
- <div className="flex justify-end pt-4 border-t">
- <Button variant="outline" onClick={onClose}>
- Close
- </Button>
- </div>
- </DialogContent>
- </Dialog>
- );
-};
diff --git a/src/components/SalesChannels/CreateSalesChannelWizardV2.tsx b/src/components/SalesChannels/CreateSalesChannelWizardV2.tsx
deleted file mode 100644
index a9d40e64..00000000
--- a/src/components/SalesChannels/CreateSalesChannelWizardV2.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import { Wizard, WizardStep } from "components/ui/wizard";
-import { useEntitySelected } from "context/EntityProvider";
-import {
- SalesChannelFormData,
- useSalesChannelWizard,
-} from "hooks/useSalesChannelWizard";
-import React, { useEffect, useMemo, useState } from "react";
-import { useForm } from "react-hook-form";
-import { SalesChannelType } from "src/constants";
-import {
- EntitySalesChannel,
- useExecuteSearchCohortpriceleveldbGet,
- useSearchPaymentMethodTypes,
-} from "src/spring-generated";
-import { SalesChannelBasicInfoStep } from "./SalesChannelBasicInfoStep";
-import { SalesChannelPaymentMethodsStep } from "./SalesChannelPaymentMethodsStep";
-
-interface CreateSalesChannelWizardV2Props {
- isOpen: boolean;
- onClose: () => void;
- onSave: (channel: EntitySalesChannel) => void;
-}
-
-export const CreateSalesChannelWizardV2: React.FC<
- CreateSalesChannelWizardV2Props
-> = ({ isOpen, onClose, onSave }) => {
- const [entity] = useEntitySelected();
- const [selectedDepartments, setSelectedDepartments] = useState<number[]>([]);
- const [isSubmitting, setIsSubmitting] = useState(false);
-
- // Fetch payment method types and price levels for default values
- const { data: paymentMethodTypesData } = useSearchPaymentMethodTypes({
- size: 100,
- });
-
- const { data: priceLevels } = useExecuteSearchCohortpriceleveldbGet({
- cohortId: entity?.cohortId,
- size: 1,
- });
-
- const defaultValues = useMemo(() => {
- return {
- entityId: entity?.id,
- salesChannelTypeId: SalesChannelType.UNINTEGRATED,
- active: false,
- taxable: false,
- name: "",
- autoAddNewDepartments: false,
- allowNegativeInventory: false,
- departmentIds: [],
- paymentMethods: [],
- };
- }, [entity?.id]);
-
- const form = useForm<SalesChannelFormData>({
- defaultValues,
- });
-
- // Set payment methods when data becomes available
- useEffect(() => {
- if (!isOpen) return;
- const firstPriceLevel = priceLevels?._embedded?.cohortPriceLevelDBs?.[0];
- const availablePaymentMethods = paymentMethodTypesData?.content || [];
-
- if (
- availablePaymentMethods.length > 0 &&
- firstPriceLevel &&
- form.getValues("paymentMethods").length === 0
- ) {
- const defaultPaymentMethods = availablePaymentMethods.map(
- (type, index) => ({
- paymentMethodType: type.name,
- cohortPriceLevelId: firstPriceLevel.id,
- displayOnPayButton: true,
- isDefault: index === 0, // First one (usually CASH) is default
- entityId: entity?.id || 0,
- entitySalesChannelId: 0,
- isArchived: false,
- }),
- );
-
- form.setValue("paymentMethods", defaultPaymentMethods);
- }
- }, [
- isOpen,
- paymentMethodTypesData?.content,
- priceLevels?._embedded?.cohortPriceLevelDBs,
- entity?.id,
- form,
- ]);
-
- const handleClose = () => {
- onClose();
- form.reset();
- setSelectedDepartments([]);
- setIsSubmitting(false);
- };
-
- const { handleComplete } = useSalesChannelWizard({
- onSuccess: (channel) => {
- onSave(channel);
- setIsSubmitting(false);
- handleClose();
- },
- onClose: handleClose,
- });
-
- const handleCompleteWizard = async (data?: unknown) => {
- setIsSubmitting(true);
- try {
- await handleComplete(form.getValues());
- } catch (error) {
- setIsSubmitting(false);
- // Error is already handled by the hook
- }
- };
-
- const handleReset = () => {
- form.reset(defaultValues);
- setSelectedDepartments([]);
- setIsSubmitting(false);
- };
-
- // Create wizard steps
- const steps: WizardStep[] = useMemo(
- () => [
- {
- title: "Basic Information",
- description: "Enter the basic details for your sales channel",
- content: (
- <SalesChannelBasicInfoStep
- form={form}
- selectedDepartments={selectedDepartments}
- setSelectedDepartments={setSelectedDepartments}
- />
- ),
- validation: () => {
- const values = form.getValues();
- return (
- !!values.name?.trim() && values.salesChannelTypeId !== undefined
- );
- },
- },
- {
- title: "Payment Methods",
- description: "Configure payment methods and price levels",
- content: (
- <SalesChannelPaymentMethodsStep
- form={form}
- paymentMethodTypes={paymentMethodTypesData?.content || []}
- />
- ),
- validation: () => {
- const values = form.getValues();
- const hasPaymentMethods = values.paymentMethods?.length > 0;
- const hasDefault = values.paymentMethods?.some((pm) => pm.isDefault);
- const allHavePriceLevels = values.paymentMethods?.every(
- (pm) => pm.cohortPriceLevelId && pm.cohortPriceLevelId > 0,
- );
- return hasPaymentMethods && hasDefault && allHavePriceLevels;
- },
- },
- ],
- [
- form,
- selectedDepartments,
- setSelectedDepartments,
- paymentMethodTypesData?.content,
- ],
- );
-
- return (
- <Wizard
- steps={steps}
- isOpen={isOpen}
- onClose={handleClose}
- onComplete={handleCompleteWizard}
- onReset={handleReset}
- title="Create Sales Channel"
- description="Set up a new sales channel."
- completeButtonText="Create Channel"
- autoResetOnComplete={false}
- isLoading={isSubmitting}
- form={form}
- />
- );
-};
-
-export default CreateSalesChannelWizardV2;
diff --git a/src/components/SalesChannels/PaymentMethodManager.tsx b/src/components/SalesChannels/PaymentMethodManager.tsx
deleted file mode 100644
index 686f0aac..00000000
--- a/src/components/SalesChannels/PaymentMethodManager.tsx
+++ /dev/null
@@ -1,474 +0,0 @@
-import { Button } from "components/ui/button";
-import { Card, CardContent, CardHeader } from "components/ui/card";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "components/ui/dropdown-menu";
-import { captureException } from "config/sentry/TransformitySentry";
-import { useEntitySelected } from "context/EntityProvider";
-import { SalesChannelFormData } from "hooks/useSalesChannelWizard";
-import { Archive, ChevronDown, Loader2, Plus } from "lucide-react";
-import React, { useEffect, useMemo, useState } from "react";
-import { useFieldArray, UseFormReturn } from "react-hook-form";
-import { toast } from "sonner";
-import {
- useCreateEntitySalesChannelPaymentMethod,
- useExecuteSearchCohortpriceleveldbGet,
- useGetEntitySalesChannelById,
- useSearchEntitySalesChannelPaymentMethods,
- useSearchPaymentMethodTypes,
- useUpdateEntitySalesChannelPaymentMethod,
- useUpsertEntitySalesChannel,
-} from "src/spring-generated";
-import { extractAxios400ErrorMessage } from "utils/errors";
-import { ArchivedPaymentMethodsModal } from "./ArchivedPaymentMethodsModal";
-import { PaymentMethodTable } from "./PaymentMethodTable";
-
-interface PaymentMethodManagerProps {
- form: UseFormReturn<SalesChannelFormData>;
- salesChannelId: number;
-}
-
-export const PaymentMethodManager: React.FC<PaymentMethodManagerProps> = ({
- form,
- salesChannelId,
-}) => {
- const [entity] = useEntitySelected();
- const [priceLevelSearch, setPriceLevelSearch] = useState<string>();
- const [isArchivedModalOpen, setIsArchivedModalOpen] = useState(false);
-
- // Fetch sales channel data to get default payment method
- const { data: salesChannel } = useGetEntitySalesChannelById(salesChannelId, {
- query: {
- enabled: !!salesChannelId && salesChannelId > 0,
- },
- });
-
- // Fetch payment method types from API
- const { data: paymentMethodTypesData } = useSearchPaymentMethodTypes({
- size: 100,
- });
-
- // Fetch existing payment methods
- const {
- data: existingPaymentMethods,
- isLoading: isLoadingExistingPaymentMethods,
- refetch: refetchPaymentMethods,
- } = useSearchEntitySalesChannelPaymentMethods(
- {
- entitySalesChannelId: salesChannelId,
- entityId: entity?.id || 0,
- isArchived: false,
- page: 0,
- size: 100,
- },
- {
- query: {
- enabled: !!salesChannelId && !!entity?.id,
- queryKey: ["payment-methods", salesChannelId, entity?.id],
- },
- },
- );
-
- const { data: priceLevels, isFetching: isPriceLevelsFetching } =
- useExecuteSearchCohortpriceleveldbGet({
- cohortId: entity?.cohortId,
- size: 100,
- name: priceLevelSearch,
- });
-
- const {
- fields: paymentMethods,
- append,
- remove,
- update,
- } = useFieldArray({
- control: form.control,
- name: "paymentMethods",
- keyName: "fieldArrayUniqueId", // Use the 'id' field as the unique identifier
- });
- console.log("paymentMethods", paymentMethods);
-
- // API mutations for auto-save
- const {
- mutateAsync: createPaymentMethod,
- isPending: isCreatingPaymentMethod,
- } = useCreateEntitySalesChannelPaymentMethod();
- const {
- mutateAsync: updatePaymentMethod,
- isPending: isUpdatingPaymentMethod,
- } = useUpdateEntitySalesChannelPaymentMethod();
- const { mutateAsync: upsertSalesChannel, isPending: isUpdatingSalesChannel } =
- useUpsertEntitySalesChannel();
-
- // Loading states for specific actions
- const [loadingActions, setLoadingActions] = useState<Record<string, boolean>>(
- {},
- );
-
- // Populate payment methods when they load from API
- useEffect(() => {
- console.log("existingPaymentMethods", existingPaymentMethods);
- if (
- existingPaymentMethods?.content &&
- existingPaymentMethods.content.length > 0
- ) {
- const convertedPaymentMethods = existingPaymentMethods.content.map(
- (pm) => ({
- id: pm.id, // This should be the escmp_ prefixed ID
- paymentMethodType: pm.paymentMethodType,
- cohortPriceLevelId: pm.cohortPriceLevelId,
- displayOnPayButton: pm.displayOnPayButton,
- entityId: entity?.id || 0,
- entitySalesChannelId: pm.entitySalesChannelId,
- isDefault: pm.id === salesChannel?.defaultPaymentMethodId,
- isArchived: pm.isArchived || false,
- }),
- );
-
- console.log("convertedPaymentMethods", convertedPaymentMethods);
- form.setValue("paymentMethods", convertedPaymentMethods);
- }
- }, [
- existingPaymentMethods,
- salesChannel?.defaultPaymentMethodId,
- form,
- entity?.id,
- ]);
-
- // Memoized filtered payment method options
- const availablePaymentMethodOptions = useMemo(() => {
- const allTypes = paymentMethodTypesData?.content || [];
- const selectedTypes = paymentMethods.map((pm) => pm.paymentMethodType);
-
- return allTypes
- .filter((type) => !selectedTypes.includes(type.name))
- .map((type) => ({
- value: type.name,
- label: type.name,
- }));
- }, [paymentMethodTypesData?.content, paymentMethods]);
-
- const addPaymentMethod = async (type: string) => {
- const firstPriceLevel = priceLevels?._embedded?.cohortPriceLevelDBs?.[0];
-
- const actionKey = `add-${type}`;
- setLoadingActions((prev) => ({ ...prev, [actionKey]: true }));
-
- try {
- const newPaymentMethod = await createPaymentMethod({
- data: {
- entityId: entity?.id || 0,
- entitySalesChannelId: salesChannelId,
- paymentMethodType: type,
- cohortPriceLevelId: firstPriceLevel?.id || 0,
- displayOnPayButton: true,
- isArchived: false,
- },
- });
-
- // Add to form with the correct data from API response
- append({
- id: newPaymentMethod.id, // This should be the escmp_ prefixed ID
- paymentMethodType: newPaymentMethod.paymentMethodType,
- cohortPriceLevelId: newPaymentMethod.cohortPriceLevelId,
- displayOnPayButton: newPaymentMethod.displayOnPayButton,
- isDefault: paymentMethods.length === 0,
- entityId: entity?.id || 0,
- entitySalesChannelId: newPaymentMethod.entitySalesChannelId,
- isArchived: newPaymentMethod.isArchived || false,
- });
-
- toast.success("Payment method added successfully");
- } catch (error) {
- toast.error(
- "Failed to add payment method: " + extractAxios400ErrorMessage(error),
- );
- console.error("Error adding payment method:", error);
- captureException(error);
- } finally {
- setLoadingActions((prev) => ({ ...prev, [actionKey]: false }));
- }
- };
-
- const removePaymentMethod = async (index: number) => {
- const methodToRemove = paymentMethods[index];
-
- // Prevent deletion if it's the default or the only method
- if (
- !methodToRemove ||
- methodToRemove.isDefault ||
- paymentMethods.length <= 1
- ) {
- toast.error(
- "Cannot remove the default payment method or the last payment method",
- );
- return;
- }
-
- const actionKey = `remove-${index}`;
- setLoadingActions((prev) => ({ ...prev, [actionKey]: true }));
-
- try {
- if (methodToRemove.id) {
- await updatePaymentMethod({
- data: {
- id: methodToRemove.id,
- entityId: entity?.id || 0,
- entitySalesChannelId: salesChannelId,
- paymentMethodType: methodToRemove.paymentMethodType,
- cohortPriceLevelId: methodToRemove.cohortPriceLevelId,
- displayOnPayButton: methodToRemove.displayOnPayButton,
- isArchived: true,
- },
- });
- }
-
- remove(index);
- toast.success("Payment method archived successfully");
- } catch (error) {
- toast.error(
- "Failed to archive payment method: " +
- extractAxios400ErrorMessage(error),
- );
- console.error("Error archiving payment method:", error);
- captureException(error);
- } finally {
- setLoadingActions((prev) => ({ ...prev, [actionKey]: false }));
- }
- };
-
- const setDefaultPaymentMethod = async (index: number) => {
- const newDefaultMethod = paymentMethods[index];
- if (!newDefaultMethod?.id) return;
-
- const actionKey = `setDefault-${index}`;
- setLoadingActions((prev) => ({ ...prev, [actionKey]: true }));
-
- try {
- // Update the sales channel with the new default payment method
- await upsertSalesChannel({
- data: {
- ...form.getValues(),
- id: salesChannelId,
- defaultPaymentMethodId: newDefaultMethod.id,
- },
- });
-
- // Update form state
- paymentMethods.forEach((_, i) => {
- const currentMethod = paymentMethods[i];
- if (currentMethod) {
- update(i, {
- ...currentMethod,
- isDefault: i === index,
- });
- }
- });
-
- toast.success("Default payment method updated successfully");
- } catch (error) {
- toast.error(
- "Failed to update default payment method: " +
- extractAxios400ErrorMessage(error),
- );
- console.error("Error updating default payment method:", error);
- captureException(error);
- } finally {
- setLoadingActions((prev) => ({ ...prev, [actionKey]: false }));
- }
- };
-
- const updatePaymentMethodPriceLevel = async (
- index: number,
- priceLevelId: number,
- ) => {
- const currentMethod = paymentMethods[index];
- if (!currentMethod?.id) return;
-
- const actionKey = `updatePriceLevel-${index}`;
- setLoadingActions((prev) => ({ ...prev, [actionKey]: true }));
-
- try {
- await updatePaymentMethod({
- data: {
- id: currentMethod.id,
- entityId: entity?.id || 0,
- entitySalesChannelId: salesChannelId,
- paymentMethodType: currentMethod.paymentMethodType,
- cohortPriceLevelId: priceLevelId,
- displayOnPayButton: currentMethod.displayOnPayButton,
- isArchived: currentMethod.isArchived || false,
- },
- });
-
- update(index, {
- ...currentMethod,
- cohortPriceLevelId: priceLevelId,
- });
-
- toast.success("Price level updated successfully");
- } catch (error) {
- toast.error(
- "Failed to update price level: " + extractAxios400ErrorMessage(error),
- );
- console.error("Error updating price level:", error);
- captureException(error);
- } finally {
- setLoadingActions((prev) => ({ ...prev, [actionKey]: false }));
- }
- };
-
- const updatePaymentMethodDisplayOnPayButton = async (
- index: number,
- displayOnPayButton: boolean,
- ) => {
- const currentMethod = paymentMethods[index];
- if (!currentMethod?.id) return;
-
- const actionKey = `updateDisplay-${index}`;
- setLoadingActions((prev) => ({ ...prev, [actionKey]: true }));
-
- try {
- await updatePaymentMethod({
- data: {
- id: currentMethod.id,
- entityId: entity?.id || 0,
- entitySalesChannelId: currentMethod.entitySalesChannelId,
- paymentMethodType: currentMethod.paymentMethodType,
- cohortPriceLevelId: currentMethod.cohortPriceLevelId,
- displayOnPayButton,
- isArchived: currentMethod.isArchived || false,
- },
- });
-
- update(index, {
- ...currentMethod,
- displayOnPayButton,
- });
-
- toast.success("Display setting updated successfully");
- } catch (error) {
- toast.error(
- "Failed to update display setting: " +
- extractAxios400ErrorMessage(error),
- );
- console.error("Error updating display setting:", error);
- captureException(error);
- } finally {
- setLoadingActions((prev) => ({ ...prev, [actionKey]: false }));
- }
- };
-
- const formatPaymentMethodName = (type: string) => {
- return type
- .split("_")
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
- .join(" ");
- };
-
- if (isLoadingExistingPaymentMethods) {
- return (
- <Card>
- <CardContent>
- <div className="flex items-center justify-center py-8">
- <div className="text-center">
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
- <p className="text-gray-500">Loading payment methods...</p>
- </div>
- </div>
- </CardContent>
- </Card>
- );
- }
-
- return (
- <Card>
- <CardHeader className="pb-4">
- <div className="flex items-center justify-between">
- <div className="flex items-center gap-2">
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button
- type="button"
- variant="outline"
- disabled={availablePaymentMethodOptions.length === 0}
- >
- <Plus className="w-4 h-4 mr-2" />
- Add Payment Method
- <ChevronDown className="w-4 h-4 ml-2" />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent>
- {availablePaymentMethodOptions.map((option) => {
- const isLoading = loadingActions[`add-${option.value}`];
- return (
- <DropdownMenuItem
- key={option.value}
- onClick={() => addPaymentMethod(option.value)}
- disabled={isLoading}
- >
- {isLoading ? (
- <Loader2 className="h-3 w-3 animate-spin mr-2" />
- ) : null}
- {formatPaymentMethodName(option.label)}
- </DropdownMenuItem>
- );
- })}
- </DropdownMenuContent>
- </DropdownMenu>
- <Button
- type="button"
- variant="ghost"
- size="sm"
- onClick={() => setIsArchivedModalOpen(true)}
- className="flex items-center gap-2"
- >
- <Archive className="w-4 h-4" />
- View Archived
- </Button>
- </div>
- </div>
- </CardHeader>
- <CardContent>
- <PaymentMethodTable
- paymentMethods={paymentMethods}
- priceLevels={priceLevels?._embedded?.cohortPriceLevelDBs}
- isPriceLevelsFetching={isPriceLevelsFetching}
- onUpdatePriceLevel={updatePaymentMethodPriceLevel}
- onUpdateDisplayOnPayButton={updatePaymentMethodDisplayOnPayButton}
- onSetDefault={setDefaultPaymentMethod}
- onRemove={removePaymentMethod}
- loadingActions={loadingActions}
- isEditMode={true}
- onPriceLevelSearch={setPriceLevelSearch}
- />
- </CardContent>
-
- <ArchivedPaymentMethodsModal
- isOpen={isArchivedModalOpen}
- onClose={() => setIsArchivedModalOpen(false)}
- salesChannelId={salesChannelId}
- onPaymentMethodUnarchived={async () => {
- // Refetch payment methods and update form state
- const result = await refetchPaymentMethods();
- if (result.data?.content) {
- const converted = result.data.content.map((pm) => ({
- id: pm.id,
- paymentMethodType: pm.paymentMethodType,
- cohortPriceLevelId: pm.cohortPriceLevelId,
- displayOnPayButton: pm.displayOnPayButton,
- entityId: entity?.id || 0,
- entitySalesChannelId: pm.entitySalesChannelId,
- isDefault: pm.id === salesChannel?.defaultPaymentMethodId,
- isArchived: pm.isArchived || false,
- }));
- form.setValue("paymentMethods", converted);
- }
- }}
- />
- </Card>
- );
-};
diff --git a/src/components/SalesChannels/PaymentMethodTable.tsx b/src/components/SalesChannels/PaymentMethodTable.tsx
deleted file mode 100644
index d0b9139f..00000000
--- a/src/components/SalesChannels/PaymentMethodTable.tsx
+++ /dev/null
@@ -1,262 +0,0 @@
-import { createColumnHelper } from "@tanstack/react-table";
-import { DeleteButtonWithWarning } from "components/DeleteButtonWithWarning";
-import { TransformityTable } from "components/Table/TransformityTable";
-import { Button } from "components/ui/button";
-import { Checkbox } from "components/ui/checkbox";
-import { ComboboxSelect } from "components/ui/ComboboxSelect";
-import { Loader2, Star } from "lucide-react";
-import React, { useMemo } from "react";
-import { CohortPriceLevelDb } from "src/spring-generated";
-
-export interface PaymentMethodUI {
- id?: string;
- paymentMethodType: string;
- cohortPriceLevelId: number;
- displayOnPayButton: boolean;
- isDefault: boolean;
- entityId: number;
- entitySalesChannelId: number;
- isArchived: boolean;
-}
-
-interface PaymentMethodTableProps {
- paymentMethods: PaymentMethodUI[];
- priceLevels?: CohortPriceLevelDb[];
- isPriceLevelsFetching?: boolean;
- onUpdatePriceLevel: (index: number, priceLevelId: number) => void;
- onUpdateDisplayOnPayButton: (index: number, display: boolean) => void;
- onSetDefault: (index: number) => void;
- onRemove: (index: number) => void;
- // Loading states for edit mode (optional)
- loadingActions?: Record<string, boolean>;
- // Whether this is in edit mode (auto-save) or create mode
- isEditMode?: boolean;
- // Optional search handler for price levels
- onPriceLevelSearch?: (search: string) => void;
-}
-
-export const PaymentMethodTable: React.FC<PaymentMethodTableProps> = ({
- paymentMethods,
- priceLevels,
- isPriceLevelsFetching,
- onUpdatePriceLevel,
- onUpdateDisplayOnPayButton,
- onSetDefault,
- onRemove,
- loadingActions = {},
- isEditMode = false,
- onPriceLevelSearch,
-}) => {
- const formatPaymentMethodName = (name: string) => {
- return name
- .split("_")
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
- .join(" ");
- };
-
- const priceLevelOptions = useMemo(
- () =>
- priceLevels?.map((priceLevel) => ({
- value: priceLevel.id!.toString(),
- label: priceLevel.name,
- })) || [],
- [priceLevels],
- );
-
- // Table column helper
- const columnHelper = createColumnHelper<PaymentMethodUI>();
-
- const columns = useMemo(
- () => [
- columnHelper.accessor("paymentMethodType", {
- header: "Payment Method",
- cell: ({ row }) => (
- <div className="flex items-center space-x-2">
- <span className="font-medium">
- {formatPaymentMethodName(row.original.paymentMethodType)}
- </span>
- {row.original.isDefault && (
- <Star className="h-4 w-4 text-primary fill-primary" />
- )}
- </div>
- ),
- }),
- columnHelper.accessor("cohortPriceLevelId", {
- header: "Price Level",
- cell: ({ row }) => {
- const index = paymentMethods.findIndex(
- (pm) =>
- pm.id === row.original.id ||
- pm.paymentMethodType === row.original.paymentMethodType,
- );
- const isLoading =
- isEditMode && loadingActions[`updatePriceLevel-${index}`];
-
- return (
- <ComboboxSelect
- options={priceLevelOptions}
- value={
- row.original.cohortPriceLevelId > 0
- ? {
- value: row.original.cohortPriceLevelId.toString(),
- label:
- priceLevels?.find(
- (pl) => pl.id === row.original.cohortPriceLevelId,
- )?.name || "",
- }
- : undefined
- }
- onChange={(newValue) => {
- if (newValue && !isNaN(parseInt(newValue))) {
- onUpdatePriceLevel(index, parseInt(newValue));
- }
- }}
- onSearch={onPriceLevelSearch}
- placeholder="Select price level"
- emptyMessage="No price level found."
- isLoading={isPriceLevelsFetching || isLoading}
- className="h-8 text-sm"
- />
- );
- },
- }),
- columnHelper.accessor("displayOnPayButton", {
- header: "Show on POS",
- cell: ({ row }) => {
- const index = paymentMethods.findIndex(
- (pm) =>
- pm.id === row.original.id ||
- pm.paymentMethodType === row.original.paymentMethodType,
- );
- const isLoading =
- isEditMode && loadingActions[`updateDisplay-${index}`];
-
- return (
- <div className="flex items-center space-x-2">
- <Checkbox
- id={`show-${row.original.id || row.original.paymentMethodType}`}
- checked={row.original.displayOnPayButton}
- onCheckedChange={(checked) =>
- onUpdateDisplayOnPayButton(index, checked as boolean)
- }
- disabled={isLoading}
- className="data-[state=checked]:bg-primary data-[state=checked]:border-primary"
- />
- <label
- htmlFor={`show-${row.original.id || row.original.paymentMethodType}`}
- className="text-sm cursor-pointer"
- >
- Visible
- </label>
- {isLoading && <Loader2 className="h-3 w-3 animate-spin" />}
- </div>
- );
- },
- }),
- columnHelper.accessor("isDefault", {
- header: "Default",
- cell: ({ row }) => {
- const index = paymentMethods.findIndex(
- (pm) =>
- pm.id === row.original.id ||
- pm.paymentMethodType === row.original.paymentMethodType,
- );
- const isLoading = isEditMode && loadingActions[`setDefault-${index}`];
-
- return (
- <div className="flex justify-center">
- <Button
- type="button"
- variant={row.original.isDefault ? "default" : "outline"}
- size="sm"
- onClick={
- row.original.isDefault ? undefined : () => onSetDefault(index)
- }
- disabled={row.original.isDefault || isLoading}
- className="h-6 text-xs w-20"
- >
- {isLoading ? (
- <Loader2 className="h-3 w-3 animate-spin" />
- ) : row.original.isDefault ? (
- "Default"
- ) : (
- "Set Default"
- )}
- </Button>
- </div>
- );
- },
- }),
- columnHelper.display({
- id: "actions",
- header: "Actions",
- cell: ({ row }) => {
- const index = paymentMethods.findIndex(
- (pm) =>
- pm.id === row.original.id ||
- pm.paymentMethodType === row.original.paymentMethodType,
- );
- const isLoading = isEditMode && loadingActions[`remove-${index}`];
-
- return (
- <div className="flex items-center gap-2">
- {isEditMode ? (
- <DeleteButtonWithWarning
- onDelete={() => onRemove(index)}
- disabled={
- row.original.isDefault ||
- paymentMethods.length <= 1 ||
- isLoading
- }
- className="h-8 text-xs text-destructive border-destructive hover:bg-destructive hover:text-destructive-foreground"
- size="sm"
- variant="outline"
- >
- {isLoading ? (
- <Loader2 className="h-3 w-3 animate-spin" />
- ) : (
- "Archive"
- )}
- </DeleteButtonWithWarning>
- ) : (
- <Button
- type="button"
- onClick={() => onRemove(index)}
- disabled={
- row.original.isDefault ||
- paymentMethods.length <= 1 ||
- isLoading
- }
- className="h-8 text-xs text-destructive border-destructive hover:bg-destructive hover:text-destructive-foreground"
- size="sm"
- variant="outline"
- >
- {isLoading ? (
- <Loader2 className="h-3 w-3 animate-spin" />
- ) : (
- "Remove"
- )}
- </Button>
- )}
- </div>
- );
- },
- }),
- ],
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [
- paymentMethods,
- priceLevelOptions,
- priceLevels,
- isPriceLevelsFetching,
- loadingActions,
- isEditMode,
- onUpdatePriceLevel,
- onUpdateDisplayOnPayButton,
- onSetDefault,
- onRemove,
- ],
- );
-
- return <TransformityTable data={paymentMethods} columns={columns} />;
-};
diff --git a/src/components/SalesChannels/SalesChannelBasicInfoStep.tsx b/src/components/SalesChannels/SalesChannelBasicInfoStep.tsx
deleted file mode 100644
index f0ad27f0..00000000
--- a/src/components/SalesChannels/SalesChannelBasicInfoStep.tsx
+++ /dev/null
@@ -1,221 +0,0 @@
-import { DepartmentSelect } from "components/common/DepartmentSelect";
-import { Input } from "components/ui/input";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "components/ui/select";
-import { Switch } from "components/ui/switch";
-import { SalesChannelFormData } from "hooks/useSalesChannelWizard";
-import React from "react";
-import { Controller, UseFormReturn } from "react-hook-form";
-import { SalesChannelType, salesChannelTypeOptions } from "src/constants";
-import { useListSalesChannelTypes } from "src/spring-generated";
-
-interface SalesChannelBasicInfoStepProps {
- form: UseFormReturn<SalesChannelFormData>;
- selectedDepartments: number[];
- setSelectedDepartments: (departments: number[]) => void;
-}
-
-export const SalesChannelBasicInfoStep: React.FC<
- SalesChannelBasicInfoStepProps
-> = ({ form, selectedDepartments, setSelectedDepartments }) => {
- const { data: allowedTypes } = useListSalesChannelTypes({
- new: true,
- });
-
- const salesChannelTypeId: SalesChannelType = form.watch("salesChannelTypeId");
-
- const salesChannelOptions =
- salesChannelTypeOptions[
- salesChannelTypeId ?? SalesChannelType.UNINTEGRATED
- ];
-
- return (
- <div className="space-y-6">
- {/* Channel Name */}
- <div>
- <label
- htmlFor="name"
- className="block text-sm font-medium text-gray-700 mb-2"
- >
- Channel Name *
- </label>
- <Controller
- name="name"
- control={form.control}
- rules={{ required: "Name is required" }}
- render={({ field, fieldState: { error } }) => (
- <>
- <Input
- id="name"
- {...field}
- placeholder="Enter channel name"
- className="w-full"
- />
- {error && (
- <p className="text-red-500 text-sm mt-1">{error.message}</p>
- )}
- </>
- )}
- />
- </div>
-
- {/* Integration Type */}
- {salesChannelOptions.canEditIntegrationType && (
- <div>
- <label
- htmlFor="channelType"
- className="block text-sm font-medium text-gray-700 mb-2"
- >
- Integration Type *
- </label>
- <Controller
- name="salesChannelTypeId"
- control={form.control}
- render={({ field }) => (
- <Select
- onValueChange={(value) => field.onChange(Number(value))}
- value={field.value?.toString()}
- >
- <SelectTrigger id="channelType">
- <SelectValue placeholder="Select integration type" />
- </SelectTrigger>
- <SelectContent>
- {allowedTypes?.map((type) => (
- <SelectItem key={type.id} value={type.id.toString()}>
- {type.name}
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- )}
- />
- </div>
- )}
-
- {/* Departments */}
- <div>
- <label
- htmlFor="departmentIds"
- className="block text-sm font-medium text-gray-700 mb-2"
- >
- Departments
- </label>
- <p className="text-sm text-gray-500 mb-3">
- Select departments that should be synced to this sales channel
- </p>
- <Controller
- name="departmentIds"
- control={form.control}
- render={({ field }) => (
- <DepartmentSelect
- selectedDepartments={selectedDepartments}
- setSelectedDepartments={(val) => {
- field.onChange(val);
- setSelectedDepartments(val);
- }}
- />
- )}
- />
- </div>
-
- {/* Channel Settings */}
- <div>
- <h3 className="text-lg font-medium text-gray-900 mb-4">
- Channel Settings
- </h3>
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
- <div className="flex items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
- Taxable
- </label>
- <p className="text-xs text-muted-foreground">
- Apply taxes to transactions
- </p>
- </div>
- <Controller
- name="taxable"
- control={form.control}
- render={({ field }) => (
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- )}
- />
- </div>
-
- {salesChannelOptions.canEditActive && (
- <div className="flex items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
- Active
- </label>
- <p className="text-xs text-muted-foreground">
- Channel is currently active
- </p>
- </div>
- <Controller
- name="active"
- control={form.control}
- render={({ field }) => (
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- )}
- />
- </div>
- )}
-
- <div className="flex items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
- Auto Add New Departments
- </label>
- <p className="text-xs text-muted-foreground">
- Automatically add newly created departments
- </p>
- </div>
- <Controller
- name="autoAddNewDepartments"
- control={form.control}
- render={({ field }) => (
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- )}
- />
- </div>
-
- <div className="flex items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
- Allow Negative Inventory
- </label>
- <p className="text-xs text-muted-foreground">
- List negative inventory as in-stock
- </p>
- </div>
- <Controller
- name="allowNegativeInventory"
- control={form.control}
- render={({ field }) => (
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- )}
- />
- </div>
- </div>
- </div>
- </div>
- );
-};
diff --git a/src/components/SalesChannels/SalesChannelPaymentMethodsStep.tsx b/src/components/SalesChannels/SalesChannelPaymentMethodsStep.tsx
deleted file mode 100644
index 83245982..00000000
--- a/src/components/SalesChannels/SalesChannelPaymentMethodsStep.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import { Button } from "components/ui/button";
-import { Card, CardContent, CardHeader } from "components/ui/card";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "components/ui/dropdown-menu";
-import { useEntitySelected } from "context/EntityProvider";
-import { SalesChannelFormData } from "hooks/useSalesChannelWizard";
-import { ChevronDown, Plus } from "lucide-react";
-import React, { useMemo, useState } from "react";
-import { UseFormReturn, useFieldArray } from "react-hook-form";
-import {
- PaymentMethodTypeDb,
- useExecuteSearchCohortpriceleveldbGet,
-} from "src/spring-generated";
-import { PaymentMethodTable, PaymentMethodUI } from "./PaymentMethodTable";
-
-interface SalesChannelPaymentMethodsStepProps {
- form: UseFormReturn<SalesChannelFormData>;
- paymentMethodTypes: PaymentMethodTypeDb[];
-}
-
-export const SalesChannelPaymentMethodsStep: React.FC<
- SalesChannelPaymentMethodsStepProps
-> = ({ form, paymentMethodTypes }) => {
- const [entity] = useEntitySelected();
- const [priceLevelSearch, setPriceLevelSearch] = useState<string>();
-
- // Fetch price levels from API
- const { data: priceLevels, isFetching: isPriceLevelsFetching } =
- useExecuteSearchCohortpriceleveldbGet({
- cohortId: entity?.cohortId,
- size: 100,
- name: priceLevelSearch,
- });
-
- const {
- fields: paymentMethods,
- append,
- remove,
- update,
- } = useFieldArray({
- control: form.control,
- name: "paymentMethods",
- });
-
- // Memoized filtered payment method options (excluding already selected types)
- const availablePaymentMethodOptions = useMemo(() => {
- const allTypes = paymentMethodTypes || [];
- const selectedTypes = paymentMethods.map((pm) => pm.paymentMethodType);
-
- return allTypes
- .filter((type) => !selectedTypes.includes(type.name))
- .map((type) => ({
- value: type.name,
- label: type.name,
- }));
- }, [paymentMethodTypes, paymentMethods]);
-
- const formatPaymentMethodName = (name: string) => {
- return name
- .split("_")
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
- .join(" ");
- };
-
- // Simple handlers for create mode (no auto-save)
- const handleUpdatePriceLevel = (index: number, priceLevelId: number) => {
- const currentMethod = paymentMethods[index];
- if (currentMethod) {
- update(index, {
- ...currentMethod,
- cohortPriceLevelId: priceLevelId,
- });
- }
- };
-
- const handleUpdateDisplayOnPayButton = (index: number, display: boolean) => {
- const currentMethod = paymentMethods[index];
- if (currentMethod) {
- update(index, {
- ...currentMethod,
- displayOnPayButton: display,
- });
- }
- };
-
- const handleSetDefault = (index: number) => {
- paymentMethods.forEach((_, i) => {
- const currentMethod = paymentMethods[i];
- if (currentMethod) {
- update(i, {
- ...currentMethod,
- isDefault: i === index,
- });
- }
- });
- };
-
- const handleRemove = (index: number) => {
- const methodToRemove = paymentMethods[index];
- // Prevent deletion if it's the default or last method
- if (
- !methodToRemove ||
- methodToRemove.isDefault ||
- paymentMethods.length <= 1
- ) {
- return;
- }
- remove(index);
- };
-
- const addPaymentMethod = (type: string) => {
- const firstPriceLevel = priceLevels?._embedded?.cohortPriceLevelDBs?.[0];
- const newMethod: PaymentMethodUI = {
- paymentMethodType: type,
- cohortPriceLevelId: firstPriceLevel?.id || 0,
- displayOnPayButton: true,
- isDefault: paymentMethods.length === 0, // First one is default
- entityId: entity?.id || 0,
- entitySalesChannelId: 0, // Will be set when sales channel is created
- isArchived: false,
- };
- append(newMethod);
- };
-
- return (
- <div className="space-y-6">
- <Card>
- <CardHeader>
- <div className="flex justify-between items-center">
- <div>
- <h3 className="text-lg font-medium text-gray-900">
- Payment Methods
- </h3>
- <p className="text-sm text-gray-500">
- Configure payment methods and price levels. One method must be
- set as default.
- </p>
- </div>
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button
- type="button"
- variant="outline"
- disabled={availablePaymentMethodOptions.length === 0}
- >
- <Plus className="w-4 h-4 mr-2" />
- Add Payment Method
- <ChevronDown className="w-4 h-4 ml-2" />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent>
- {availablePaymentMethodOptions.map((option) => (
- <DropdownMenuItem
- key={option.value}
- onClick={() => addPaymentMethod(option.value)}
- >
- {formatPaymentMethodName(option.label)}
- </DropdownMenuItem>
- ))}
- </DropdownMenuContent>
- </DropdownMenu>
- </div>
- </CardHeader>
- <CardContent>
- {paymentMethods.length > 0 ? (
- <PaymentMethodTable
- paymentMethods={paymentMethods}
- priceLevels={priceLevels?._embedded?.cohortPriceLevelDBs}
- isPriceLevelsFetching={isPriceLevelsFetching}
- onUpdatePriceLevel={handleUpdatePriceLevel}
- onUpdateDisplayOnPayButton={handleUpdateDisplayOnPayButton}
- onSetDefault={handleSetDefault}
- onRemove={handleRemove}
- isEditMode={false}
- />
- ) : (
- <div className="text-center py-8 text-gray-500">
- <p>Loading payment methods...</p>
- <p className="text-sm">
- Please wait while we load available payment methods.
- </p>
- </div>
- )}
- </CardContent>
- </Card>
- </div>
- );
-};
diff --git a/src/components/SalesChannels/UpsertSalesChannelDialog.tsx b/src/components/SalesChannels/UpsertSalesChannelDialog.tsx
new file mode 100644
index 00000000..7bc15ac8
--- /dev/null
+++ b/src/components/SalesChannels/UpsertSalesChannelDialog.tsx
@@ -0,0 +1,406 @@
+import { useToast } from "@chakra-ui/react";
+import { DepartmentSelect } from "components/common/DepartmentSelect";
+import { CenteredLayout } from "components/layouts/CenteredLayout";
+import { Button } from "components/ui/button";
+import { ComboboxSelect } from "components/ui/ComboboxSelect";
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "components/ui/dialog";
+import { Input } from "components/ui/input";
+import { LoadingSpinner } from "components/ui/loading-spinner";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "components/ui/select";
+import { Switch } from "components/ui/switch";
+import { useEntitySelected } from "context/EntityProvider";
+import { useGetAllDepartmentsForEntity } from "hooks/useGetAllDepartmentsForEntity";
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import { Controller, useForm } from "react-hook-form";
+import { SalesChannelType, salesChannelTypeOptions } from "src/constants";
+import {
+ EntitySalesChannel,
+ UpsertSalesChannel,
+ useExecuteSearchCohortpriceleveldbGet,
+ useFindPriceLevelById,
+ useListSalesChannelDepartments,
+ useListSalesChannelTypes,
+ useUpsertEntitySalesChannel,
+} from "src/spring-generated";
+
+type UpsertSalesChannelDialogProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ channel?: EntitySalesChannel;
+ onSave: (channel: EntitySalesChannel) => void;
+};
+
+export const UpsertSalesChannelDialog: React.FC<
+ UpsertSalesChannelDialogProps
+> = ({ isOpen, onClose, channel, onSave }) => {
+ const { departmentKeyMap } = useGetAllDepartmentsForEntity();
+ const [selectedDepartments, setSelectedDepartments] = useState<number[]>([]);
+ const [entity] = useEntitySelected();
+ const {
+ data: entitySalesChannelDepartments,
+ isFetching: isLoadingSalesChannelDepartments,
+ } = useListSalesChannelDepartments(channel?.id ?? 0, {
+ query: {
+ enabled: !!channel?.id,
+ },
+ });
+
+ const defaultValues = useMemo(() => {
+ return {
+ entityId: entity?.id,
+ salesChannelTypeId:
+ channel?.salesChannelTypeId || SalesChannelType.UNINTEGRATED,
+ active: channel?.active ?? false,
+ taxable: channel?.taxable ?? false,
+ accountId: channel?.accountId,
+ name: channel?.name,
+ priceLevelId: channel?.priceLevelId,
+ autoAddNewDepartments: channel?.autoAddNewDepartments ?? false,
+ allowNegativeInventory: channel?.allowNegativeInventory ?? false,
+ };
+ }, [
+ channel?.accountId,
+ channel?.active,
+ channel?.allowNegativeInventory,
+ channel?.autoAddNewDepartments,
+ channel?.name,
+ channel?.priceLevelId,
+ channel?.salesChannelTypeId,
+ channel?.taxable,
+ entity?.id,
+ ]);
+
+ const { control, handleSubmit, reset, watch } = useForm<UpsertSalesChannel>({
+ defaultValues: defaultValues,
+ });
+
+ useEffect(() => {
+ reset(defaultValues);
+ }, [defaultValues, reset]);
+
+ const handleClose = useCallback(() => {
+ onClose();
+ reset();
+ setPriceLevelSearch(undefined);
+ }, [onClose, reset]);
+ const selectedPriceLevelId = watch("priceLevelId");
+ const toast = useToast();
+ const { data: allowedTypes } = useListSalesChannelTypes({
+ new: !channel,
+ });
+ const [priceLevelSearch, setPriceLevelSearch] = useState<string>();
+ const { data: selectedPriceLevel } = useFindPriceLevelById(
+ selectedPriceLevelId ?? 0,
+ {
+ query: {
+ enabled: !!selectedPriceLevelId,
+ },
+ },
+ );
+ const { data: priceLevels, isFetching: isPriceLevelsFetching } =
+ useExecuteSearchCohortpriceleveldbGet({
+ cohortId: entity?.cohortId,
+ size: 30,
+ name: priceLevelSearch,
+ });
+ const { mutateAsync: upsertSalesChannel, isPending: isLoading } =
+ useUpsertEntitySalesChannel({
+ mutation: {
+ onSuccess: (resp) => {
+ toast({
+ status: "success",
+ title: "Sales channel updated",
+ description: "Your sales channel has been updated",
+ });
+ onSave(resp);
+ handleClose();
+ },
+ onError: (err) => {
+ toast({
+ status: "error",
+ title: "Error",
+ description: "An error occurred while updating the sales channel",
+ });
+ },
+ },
+ });
+
+ const salesChannelTypeId: SalesChannelType = watch("salesChannelTypeId");
+
+ useEffect(() => {
+ if (channel) {
+ if (entitySalesChannelDepartments) {
+ reset({
+ ...channel,
+ departmentIds: entitySalesChannelDepartments.map(
+ (department) => department.id.departmentId,
+ ),
+ });
+ setSelectedDepartments(
+ entitySalesChannelDepartments.map(
+ (department) => department.id.departmentId,
+ ),
+ );
+ } else {
+ reset(channel);
+ }
+ }
+ }, [channel, departmentKeyMap, entitySalesChannelDepartments, reset]);
+
+ const onSubmit = async (data: UpsertSalesChannel) => {
+ await upsertSalesChannel({
+ data,
+ });
+ };
+
+ const priceLevelOptions = useMemo(
+ () =>
+ priceLevels?._embedded?.cohortPriceLevelDBs?.map((priceLevel) => ({
+ value: priceLevel.id!.toString(),
+ label: priceLevel.name,
+ })) || [],
+ [priceLevels],
+ );
+
+ const salesChannelOptions =
+ salesChannelTypeOptions[
+ salesChannelTypeId ?? SalesChannelType.UNINTEGRATED
+ ] ?? salesChannelTypeOptions[SalesChannelType.UNINTEGRATED];
+
+ return (
+ <Dialog open={isOpen} onOpenChange={handleClose}>
+ <DialogContent>
+ <DialogHeader>
+ <DialogTitle>{channel ? "Edit" : "Add"} Sales Channel</DialogTitle>
+ </DialogHeader>
+ {isLoadingSalesChannelDepartments ? (
+ <CenteredLayout>
+ <LoadingSpinner />
+ </CenteredLayout>
+ ) : (
+ <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
+ <div>
+ <label
+ htmlFor="name"
+ className="block text-sm font-medium text-gray-700"
+ >
+ Name
+ </label>
+ <Controller
+ name="name"
+ control={control}
+ rules={{ required: "Name is required" }}
+ render={({ field, fieldState: { error } }) => (
+ <>
+ <Input
+ id="name"
+ {...field}
+ placeholder="Enter channel name"
+ />
+ {error && (
+ <p className="text-red-500 text-sm mt-1">
+ {error.message}
+ </p>
+ )}
+ </>
+ )}
+ />
+ </div>
+ {salesChannelOptions.canEditPriceLevel && (
+ <div>
+ <label
+ htmlFor="priceLevelId"
+ className="block text-sm font-medium text-gray-700"
+ >
+ Price Level
+ </label>
+ <Controller
+ name="priceLevelId"
+ control={control}
+ rules={{ required: "Price Level is required" }}
+ render={({ field, fieldState: { error } }) => (
+ <>
+ <ComboboxSelect
+ options={priceLevelOptions}
+ value={
+ field.value
+ ? {
+ value: field.value?.toString() || "",
+ label: selectedPriceLevel?.name || "",
+ }
+ : undefined
+ }
+ onChange={(newValue) => field.onChange(newValue)}
+ onSearch={setPriceLevelSearch}
+ placeholder="Select price level"
+ emptyMessage="No price level found."
+ isLoading={isPriceLevelsFetching}
+ />
+ {error && (
+ <p className="text-red-500 text-sm mt-1">
+ {error.message}
+ </p>
+ )}
+ </>
+ )}
+ />
+ </div>
+ )}
+ {salesChannelOptions.canEditIntegrationType && (
+ <div>
+ <label
+ htmlFor="channelType"
+ className="block text-sm font-medium text-gray-700"
+ >
+ Integration Type
+ </label>
+ <Controller
+ name="salesChannelTypeId"
+ control={control}
+ render={({ field }) => (
+ <Select
+ onValueChange={(value) => field.onChange(Number(value))}
+ value={field.value.toString()}
+ >
+ <SelectTrigger id="channelType">
+ <SelectValue placeholder="Select integration type" />
+ </SelectTrigger>
+ <SelectContent>
+ {allowedTypes?.map((type) => (
+ <SelectItem key={type.id} value={type.id.toString()}>
+ {type.name}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ )}
+ />
+ </div>
+ )}
+ <div className="flex items-center space-x-2">
+ <Controller
+ name="taxable"
+ control={control}
+ render={({ field }) => (
+ <Switch
+ id="taxable"
+ checked={field.value}
+ onCheckedChange={field.onChange}
+ />
+ )}
+ />
+ <label
+ htmlFor="taxable"
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+ >
+ Taxable
+ </label>
+ </div>
+ {salesChannelOptions.canEditActive && (
+ <div className="flex items-center space-x-2">
+ <Controller
+ name="active"
+ control={control}
+ render={({ field }) => (
+ <Switch
+ id="active"
+ checked={field.value}
+ onCheckedChange={field.onChange}
+ />
+ )}
+ />
+ <label
+ htmlFor="active"
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+ >
+ Active
+ </label>
+ </div>
+ )}
+
+ <div>
+ <label htmlFor="departmentIds">Departments</label>
+ <p className="text-sm text-gray-500">
+ Select departments that should be synced to this sales channel
+ </p>
+ <Controller
+ name="departmentIds"
+ control={control}
+ render={({ field }) => (
+ <DepartmentSelect
+ selectedDepartments={selectedDepartments}
+ setSelectedDepartments={(val) => {
+ field.onChange(val);
+ setSelectedDepartments(val);
+ }}
+ />
+ )}
+ />
+ </div>
+
+ <div className="flex items-center space-x-2">
+ <Controller
+ name="autoAddNewDepartments"
+ control={control}
+ render={({ field }) => (
+ <Switch
+ id="autoAddNewDepartments"
+ checked={field.value}
+ onCheckedChange={field.onChange}
+ />
+ )}
+ />
+ <label
+ htmlFor="autoAddNewDepartments"
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+ >
+ Auto Add Newly Created Departments
+ </label>
+ </div>
+
+ <div className="flex items-center space-x-2">
+ <Controller
+ name="allowNegativeInventory"
+ control={control}
+ render={({ field }) => (
+ <Switch
+ id="allowNegativeInventory"
+ checked={field.value}
+ onCheckedChange={field.onChange}
+ />
+ )}
+ />
+ <label
+ htmlFor="allowNegativeInventory"
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+ >
+ List Negative Inventory As In-Stock
+ </label>
+ </div>
+
+ <DialogFooter>
+ <Button type="button" variant="outline" onClick={handleClose}>
+ Cancel
+ </Button>
+ <Button type="submit" isLoading={isLoading}>
+ Save Changes
+ </Button>
+ </DialogFooter>
+ </form>
+ )}
+ </DialogContent>
+ </Dialog>
+ );
+};
diff --git a/src/components/SalesReportComponents/LineChart.tsx b/src/components/SalesReportComponents/LineChart.tsx
index e608a582..691ed865 100644
--- a/src/components/SalesReportComponents/LineChart.tsx
+++ b/src/components/SalesReportComponents/LineChart.tsx
@@ -52,7 +52,6 @@ export const LineChart: React.FC<LineChartProps> = ({
const newData = new Map([...sortedData.entries()].slice(0, numDisplayed));
setDisplayData(newData);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, numDisplayed]);
return (
diff --git a/src/components/SalesReportComponents/PieChart.tsx b/src/components/SalesReportComponents/PieChart.tsx
index 70109717..f40ce443 100644
--- a/src/components/SalesReportComponents/PieChart.tsx
+++ b/src/components/SalesReportComponents/PieChart.tsx
@@ -31,7 +31,6 @@ export const PieChart: React.FC<PieChartProps> = ({ id, data, isPercent }) => {
});
}
setDisplayData(newData);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, numDisplayed]);
return (
diff --git a/src/components/SalesScreenComponents/Modals/CartHoldsModal.tsx b/src/components/SalesScreenComponents/Modals/CartHoldsModal.tsx
index a949921e..760574db 100644
--- a/src/components/SalesScreenComponents/Modals/CartHoldsModal.tsx
+++ b/src/components/SalesScreenComponents/Modals/CartHoldsModal.tsx
@@ -18,33 +18,26 @@ import {
useToast,
VStack,
} from "@chakra-ui/react";
-import { usePGlite } from "@electric-sql/pglite-react";
import { useQueryClient } from "@tanstack/react-query";
import { DeleteButtonWithWarning } from "components/DeleteButtonWithWarning";
-import {
- type RetrieveItemsByUpc,
- RetrieveItemsByUpcQuery,
-} from "components/pg-lite/queries/RetrieveItemsByUpc";
import { useTransactionReceipt } from "components/TransactionsComponents/useTransactionReceipt";
import { captureException } from "config/sentry/TransformitySentry";
import { useAuthorization } from "context/AuthorizationContext/useAuthorizationContext";
-import {
- useEntitySelected,
- useLoyaltyProgramIdOptional,
-} from "context/EntityProvider";
+import { useEntity, useLoyaltyProgramIdOptional } from "context/EntityProvider";
import { useSalesContext } from "context/Sales/SalesContext";
-import type { itemT } from "context/Sales/SalesContextProvider";
+import { itemT } from "context/Sales/SalesContextProvider";
import { format } from "date-fns";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { Link } from "react-router-dom";
import {
- type CartDiscountType,
- type Discount,
+ CartDiscountType,
+ Discount,
+ getItemByIdQueryOptions,
getLoyaltyCustomerQueryOptions,
- type LoyaltyCustomer,
- type TransactionDataOutput,
- type TransactionOutput,
+ LoyaltyCustomer,
+ TransactionDataOutput,
+ TransactionOutput,
TransactionStatus,
useCancelTransaction,
useGetLoyaltyCustomer,
@@ -52,7 +45,7 @@ import {
useGetTransactions,
} from "src/generated";
import {
- type TransactionHoldDb,
+ TransactionHoldDb,
useCreateTransactionHold,
useDeleteTransactionHold,
useListHolds,
@@ -82,7 +75,7 @@ const CartDeleteButton = ({
isDeleting: boolean;
}) => {
const { mutateAsync: cancelTransaction, isPending } = useCancelTransaction(
- transactionId,
+ transactionId!,
{},
{
mutation: {
@@ -152,8 +145,6 @@ export const CartHoldCard = (props: {
const [loadingCart, setLoadingCart] = useState(false);
const queryClient = useQueryClient();
const { id: programId } = useLoyaltyProgramIdOptional();
- const [entity] = useEntitySelected();
- const db = usePGlite();
const { closeModal, onCartDelete, transactionData } = props;
const { printReceipt } = useTransactionReceipt();
@@ -252,7 +243,7 @@ export const CartHoldCard = (props: {
transactionId: originalTransactionId,
upsertTransactionHold: {
id: "",
- name: `${customer?.name ? `${customer.name} - ` : ""}${format(new Date(), "MMM dd yyyy hh:mm a")}`,
+ name: `${customer?.name ? customer.name + " - " : ""}${format(new Date(), "MMM dd yyyy hh:mm a")}`,
},
},
});
@@ -268,35 +259,19 @@ export const CartHoldCard = (props: {
const newItemDetails = new Map() as itemT;
for (const item of data.transactionItems) {
- if (!item.itemId) {
- newItemDetails.set(item.id, {
- ...item,
- tax: item.tax,
- taxRate: item.taxRate ?? 0,
- promotionItems: item.promotionItems,
- discount: item.discount ?? 0,
- itemId: item.itemId,
- transactionId: props.cart.transaction.id,
- department: item.department ?? 0,
- });
- continue;
- }
- const options = RetrieveItemsByUpcQuery(
- entity.id,
- null,
- [item.itemId],
- );
- const eRes = await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
- );
+ const entityItemOptions = !!item.itemId
+ ? getItemByIdQueryOptions(item.itemId)
+ : undefined;
+ const entityItem = !!entityItemOptions
+ ? await queryClient.fetchQuery(entityItemOptions)
+ : undefined;
newItemDetails.set(item.id, {
...item,
tax: item.tax,
taxRate: item.taxRate ?? 0,
promotionItems: item.promotionItems,
discount: item.discount ?? 0,
- item: eRes.rows?.[0],
+ item: entityItem,
itemId: item.itemId,
transactionId: props.cart.transaction.id,
department: item.department ?? 0,
@@ -406,12 +381,15 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
isOpen,
onClose,
}) => {
- const [entity] = useEntitySelected();
+ const [entity] = useEntity();
+ const queryClient = useQueryClient();
const [currentPage, setCurrentPage] = useState(1);
const pageSize = 5; // Number of carts per page
const {
items: itemDetails = new Map(),
+ taxExempt,
+ discount,
customer,
clearCart,
transactionId,
@@ -434,7 +412,7 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
refetch: refetchHolds,
} = useGetTransactions(
{
- entityId: entity.id,
+ entityId: entity?.id ?? 0,
page: currentPage - 1, // API uses 0-based indexing
size: pageSize,
hasHold: true, // Only get transactions with holds
@@ -468,10 +446,7 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
},
},
);
- const holdsMap = useMemo(
- () => new Map(holdsData?.content?.map((hold) => [hold.id, hold])),
- [holdsData?.content],
- );
+ const holdsMap = new Map(holdsData?.content?.map((hold) => [hold.id, hold]));
// Use the mapped data from the API instead of localStorage, filtering out carts without ids
const apiCarts: Cart[] = useMemo(() => {
@@ -557,7 +532,7 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
onClose();
reset();
await overrideLogout();
- } catch {
+ } catch (error) {
// Error handling is done in the mutation onError callback
toast({
title: "Failed to save cart",
@@ -623,7 +598,7 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
autoFocus
width={"100%"}
onFocus={(e) => e.currentTarget.select()}
- defaultValue={`${customer ? `${customer.name} - ` : ""}${format(new Date(), "MMM dd yyyy")}`}
+ defaultValue={`${customer ? customer.name + " - " : ""}${format(new Date(), "MMM dd yyyy")}`}
{...registerForm("name", { required: true })}
placeholder="Cart Name"
/>
@@ -650,10 +625,10 @@ export const CartHoldsModal: React.FC<CartHoldsModalProps> = ({
) : (
<>
<VStack spacing={3} w="100%" flex={1}>
- {apiCarts.map((cart) => (
+ {apiCarts.map((cart, index) => (
<CartHoldCard
cart={cart}
- key={cart.transaction.id}
+ key={index}
transactionData={
transactionData?.transactions?.find(
(t) => t.id === cart.transaction.id,
diff --git a/src/components/SalesScreenComponents/Modals/ManualCardPunchModal.tsx b/src/components/SalesScreenComponents/Modals/ManualCardPunchModal.tsx
index 36d0c63a..784beaf1 100644
--- a/src/components/SalesScreenComponents/Modals/ManualCardPunchModal.tsx
+++ b/src/components/SalesScreenComponents/Modals/ManualCardPunchModal.tsx
@@ -7,24 +7,12 @@ import StripeCardPunchIn from "components/paymentProcessor/StripeCardPunchIn";
import WorldpayManualPaymentModal from "components/paymentProcessor/worldpay/WorldpayManualPaymentModal";
import { useEntitySelected } from "context/EntityProvider";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
-import {
- EntitySalesChannel,
- EntitySalesChannelPaymentMethod,
-} from "src/spring-generated";
-import { currencyFormat } from "src/utils/currencyUtils";
const apiKey = import.meta.env.VITE_APP_STRIPE_PUBLIC_KEY;
-export type CreditCardPriceOption = {
- method: EntitySalesChannelPaymentMethod;
- total: number;
-};
-
export type ManualCardPunchModalProps = {
isOpen: boolean;
onClose: () => void;
- onSubmit: (selectedPriceOption?: CreditCardPriceOption) => void;
- selectedPriceOption?: CreditCardPriceOption;
- salesChannel?: EntitySalesChannel; // Make it optional for contexts without sale page config
+ onSubmit: () => void;
};
const stripePromise = loadStripe(apiKey);
@@ -32,86 +20,34 @@ export const ManualCardPunchModal = ({
isOpen,
onClose,
onSubmit,
- selectedPriceOption,
- salesChannel: propSalesChannel,
}: ManualCardPunchModalProps) => {
- const {
- transactionTotalPrice,
- salesChannel,
- selectedSalesChannel: contextSelectedSalesChannel,
- } = useSalesPaymentContext();
+ const { transactionTotalPrice } = useSalesPaymentContext();
const [entity] = useEntitySelected();
- // Use passed salesChannel prop or fallback to the selectedSalesChannel from context or salesChannel
- const selectedSalesChannel =
- propSalesChannel || contextSelectedSalesChannel || salesChannel;
- // Use the provided price option or fall back to default
- const defaultPrice = transactionTotalPrice();
- const defaultMethod = selectedSalesChannel?.defaultPaymentMethodId;
- const defaultOption = {
- method: { id: defaultMethod },
- total: defaultPrice,
- } as CreditCardPriceOption;
- const priceToUse = selectedPriceOption?.total || defaultPrice;
-
const options: StripeElementsOptionsMode = {
mode: "payment",
currency: "usd",
- amount: Math.trunc(priceToUse * 100),
+ amount: Math.trunc(transactionTotalPrice() * 100),
paymentMethodCreation: "manual",
paymentMethodTypes: ["card"],
};
- const handleSubmit = () => {
- onSubmit(selectedPriceOption);
- };
-
return (
<>
{entity.paymentProcessor?.processorName?.toLowerCase() === "worldpay" &&
- isOpen && (
- <WorldpayManualPaymentModal
- onFormSubmit={handleSubmit}
- priceSelected={selectedPriceOption ?? defaultOption}
- />
- )}
+ isOpen && <WorldpayManualPaymentModal onFormSubmit={onSubmit} />}
{entity.paymentProcessor?.processorName?.toLowerCase() !== "worldpay" && (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent p={10}>
- {/* Show selected price info */}
- {selectedPriceOption && (
- <div className="mb-4 p-3 bg-gray-50 rounded-md">
- <div className="text-sm text-gray-600">
- Processing payment for:{" "}
- <span className="font-semibold">
- {currencyFormat("USD", selectedPriceOption.total)}
- </span>
- {selectedPriceOption.method.id !== "default" && (
- <span className="text-gray-500 ml-2">
- (Payment Method: {selectedPriceOption.method.id})
- </span>
- )}
- </div>
- </div>
- )}
-
{entity.paymentProcessor?.processorName?.toLowerCase() ===
"stripe" && (
<Elements stripe={stripePromise} options={options}>
- <StripeCardPunchIn
- onSubmit={handleSubmit}
- priceSelected={selectedPriceOption ?? defaultOption}
- />
+ <StripeCardPunchIn onSubmit={onSubmit} />
</Elements>
)}
{entity.paymentProcessor?.processorName?.toLowerCase() ===
- "finix" && (
- <FinixPaymentModal
- onFormSubmit={handleSubmit}
- priceSelected={selectedPriceOption ?? defaultOption}
- />
- )}
+ "finix" && <FinixPaymentModal onFormSubmit={onSubmit} />}
</ModalContent>
</Modal>
)}
diff --git a/src/components/SalesScreenComponents/Modals/MultipleChoicesModal.tsx b/src/components/SalesScreenComponents/Modals/MultipleChoicesModal.tsx
index 09330931..f7c5bb8c 100644
--- a/src/components/SalesScreenComponents/Modals/MultipleChoicesModal.tsx
+++ b/src/components/SalesScreenComponents/Modals/MultipleChoicesModal.tsx
@@ -11,47 +11,47 @@ import {
Text,
UseDisclosureReturn,
} from "@chakra-ui/react";
-import { RetrieveItemsByUpc } from "components/pg-lite/queries/RetrieveItemsByUpc";
import { useSalesContext } from "context/Sales/SalesContext";
import { useEntityConfig } from "hooks/useEntityConfig";
import { get } from "lodash-es";
import { useMemo, useRef } from "react";
+import { EntityItemDetail } from "src/generated";
import { EntityConfigKey } from "src/generated/types/EntityConfigKey";
import { USDollar } from "utils/dollarFormat";
export type MultipleChoicesModalProps = {
multipleChoicesModal: UseDisclosureReturn;
transactionTotalPrice: () => number;
- multipleChoices: { items: RetrieveItemsByUpc[]; quantity: number };
+ multipleChoices: { items: EntityItemDetail[]; quantity: number };
};
-const selectButtonBgColor = (item: RetrieveItemsByUpc) => {
- const depositMultiplier = item.ci_deposit_multiplier;
- if (depositMultiplier === 1) return "blue.100";
- if (depositMultiplier === 4) return "blue.200";
- if (depositMultiplier === 8) return "blue.300";
- if (depositMultiplier === 6) return "blue.400";
- if (depositMultiplier === 12) return "blue.500";
- if (depositMultiplier === 15) return "blue.600";
- if (depositMultiplier === 18) return "blue.700";
- if (depositMultiplier === 24) return "blue.800";
- if (depositMultiplier === 30) return "blue.900";
+const selectButtonBgColor = (item: EntityItemDetail) => {
+ if (item.cohortItem.depositMultiplier === 1) return "blue.100";
+ if (item.cohortItem.depositMultiplier === 4) return "blue.200";
+ if (item.cohortItem.depositMultiplier === 8) return "blue.300";
+ if (item.cohortItem.depositMultiplier === 6) return "blue.400";
+ if (item.cohortItem.depositMultiplier === 12) return "blue.500";
+ if (item.cohortItem.depositMultiplier === 15) return "blue.600";
+ if (item.cohortItem.depositMultiplier === 18) return "blue.700";
+ if (item.cohortItem.depositMultiplier === 24) return "blue.800";
+ if (item.cohortItem.depositMultiplier === 30) return "blue.900";
return "blue";
};
-const selectButtonTextColor = (item: RetrieveItemsByUpc) => {
- const depositMultiplier = item.ci_deposit_multiplier;
- if (depositMultiplier === 1) return "black";
- if (depositMultiplier === 4) return "black";
- if (depositMultiplier === 8) return "black";
+const selectButtonTextColor = (item: EntityItemDetail) => {
+ if (item.cohortItem.depositMultiplier === 1) return "black";
+ if (item.cohortItem.depositMultiplier === 4) return "black";
+ if (item.cohortItem.depositMultiplier === 8) return "black";
return "white";
};
-const createComparator = (sortConfig: string = "ci_deposit_multiplier,asc") => {
+const createComparator = (
+ sortConfig: string = "cohortItem.depositMultiplier,asc",
+) => {
const [field, direction] = sortConfig.split(",");
const multiplier = direction === "desc" ? -1 : 1;
- return (a: RetrieveItemsByUpc, b: RetrieveItemsByUpc) => {
+ return (a: EntityItemDetail, b: EntityItemDetail) => {
if (!field) return 0;
const valueA = get(a, field);
const valueB = get(b, field);
@@ -72,7 +72,7 @@ const createComparator = (sortConfig: string = "ci_deposit_multiplier,asc") => {
};
};
-const fallbackComparator = createComparator("ci_deposit_multiplier,asc");
+const fallbackComparator = createComparator("cohortItem.name,asc");
export const MultipleChoicesModal: React.FC<MultipleChoicesModalProps> = ({
multipleChoicesModal,
@@ -82,13 +82,13 @@ export const MultipleChoicesModal: React.FC<MultipleChoicesModalProps> = ({
const { addSingleItemToCart } = useSalesContext();
const orderMultipleItemsPopupBy = useEntityConfig(
EntityConfigKey.ORDER_MULTIPLE_ITEMS_POPUP,
- "ci_deposit_multiplier,asc",
+ "cohortItem.depositMultiplier,asc",
);
const initialFocusRef = useRef(null);
const comparator = useMemo(() => {
const primaryComparator = createComparator(orderMultipleItemsPopupBy.value);
- return (a: RetrieveItemsByUpc, b: RetrieveItemsByUpc) => {
+ return (a: EntityItemDetail, b: EntityItemDetail) => {
const primaryComparison = primaryComparator(a, b);
if (primaryComparison !== 0) return primaryComparison;
return fallbackComparator(a, b);
@@ -127,7 +127,7 @@ export const MultipleChoicesModal: React.FC<MultipleChoicesModalProps> = ({
{multipleChoices.items.sort(comparator).map((choice) => {
return (
<Button
- key={choice.ei_id}
+ key={choice.id}
backgroundColor={selectButtonBgColor(choice)}
textColor={selectButtonTextColor(choice)}
overflowX={"hidden"}
@@ -144,9 +144,9 @@ export const MultipleChoicesModal: React.FC<MultipleChoicesModalProps> = ({
textAlign: "left",
}}
>
- {choice.ci_name}{" "}
+ {choice.cohortItem.name}{" "}
</Text>
- <Text>{USDollar.format(+choice.ei_price)} </Text>
+ <Text>{USDollar.format(choice.price)} </Text>
</Button>
);
})}
diff --git a/src/components/SalesScreenComponents/Modals/PayWithCashModal.tsx b/src/components/SalesScreenComponents/Modals/PayWithCashModal.tsx
index 07d54537..211afd3c 100644
--- a/src/components/SalesScreenComponents/Modals/PayWithCashModal.tsx
+++ b/src/components/SalesScreenComponents/Modals/PayWithCashModal.tsx
@@ -37,60 +37,46 @@ export interface PayWithCashModalProps {
isOpen: boolean;
onClose: () => void;
openChangeDueModal: () => void;
- selectedCashPaymentMethodId?: string;
}
export const PayWithCashModal: React.FC<PayWithCashModalProps> = ({
isOpen,
onClose,
openChangeDueModal,
- selectedCashPaymentMethodId,
}) => {
const inputRef = useRef<HTMLInputElement | null>(null);
const { setAmountPaid, transactionTotalPrice } = useSalesPaymentContext();
- // Get the cash total for the selected payment method
- const cashTotal = transactionTotalPrice({
- paymentMethodId: selectedCashPaymentMethodId,
- });
-
const form = useForm<FormValues>({
resolver: zodResolver(FormSchema),
defaultValues: {
- customAmount: Math.max(cashTotal, 0).toString(),
+ customAmount: Math.max(transactionTotalPrice(), 0).toString(),
},
});
const reset = form.reset;
useEffect(() => {
reset({
- customAmount: Math.max(cashTotal, 0).toString(),
+ customAmount: Math.max(transactionTotalPrice(), 0).toString(),
});
- }, [reset, cashTotal]);
+ }, [reset, transactionTotalPrice]);
const customAmount = +form.watch("customAmount");
const handleSubmit = useCallback(
(values: FormValues) => {
const customAmount = +values.customAmount;
- if (customAmount < cashTotal) {
+ if (customAmount < transactionTotalPrice()) {
return;
}
setAmountPaid({
amountPaid: customAmount,
paymentForm: TransactionPaymentForm.CASH,
- paymentMethodId: selectedCashPaymentMethodId,
});
openChangeDueModal();
onClose();
},
- [
- onClose,
- openChangeDueModal,
- setAmountPaid,
- cashTotal,
- selectedCashPaymentMethodId,
- ],
+ [onClose, openChangeDueModal, setAmountPaid, transactionTotalPrice],
);
return (
@@ -112,7 +98,7 @@ export const PayWithCashModal: React.FC<PayWithCashModalProps> = ({
<Text>
Amount Due:{" "}
<strong data-testid="amount-due-value">
- {USDollar.format(cashTotal)}
+ {USDollar.format(transactionTotalPrice())}
</strong>
</Text>
</Box>
@@ -142,19 +128,20 @@ export const PayWithCashModal: React.FC<PayWithCashModalProps> = ({
mr={3}
size="lg"
colorScheme="cyan"
- hidden={customAmount < cashTotal}
+ hidden={customAmount < transactionTotalPrice()}
onFocus={(e) => e.currentTarget.blur()}
isDisabled
style={{ opacity: 1.0 }}
data-testid="change-due-btn"
>
- Change Due: {USDollar.format(customAmount - cashTotal)}
+ Change Due:{" "}
+ {USDollar.format(customAmount - transactionTotalPrice())}
</Button>
<Spacer />
<Button
colorScheme="blue"
mr={3}
- isDisabled={customAmount < cashTotal}
+ isDisabled={customAmount < transactionTotalPrice()}
type="submit"
data-testid="custom-amount-submit-btn"
>
diff --git a/src/components/SalesScreenComponents/Modals/PriceLevelHelper.tsx b/src/components/SalesScreenComponents/Modals/PriceLevelHelper.tsx
deleted file mode 100644
index 537b0a91..00000000
--- a/src/components/SalesScreenComponents/Modals/PriceLevelHelper.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Button } from "@/components/ui/button";
-import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger,
-} from "@/components/ui/collapsible";
-import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
-import { ChevronDown, Info } from "lucide-react";
-import { useMemo } from "react";
-import { currencyFormat } from "src/utils/currencyUtils";
-
-interface PriceLevelHelperProps {
- transactionTotal: number;
-}
-
-const formatDiscount = (discount: number) => {
- if (Math.abs(discount) < 0.01) {
- return "NO CHANGE";
- }
- const formattedAmount = currencyFormat("USD", Math.abs(discount));
- return discount > 0 ? `-${formattedAmount}` : `+${formattedAmount}`;
-};
-
-// Format payment method name for display
-const formatPaymentMethodName = (paymentMethodType: string) => {
- return paymentMethodType
- .replace(/_/g, " ")
- .replace(/\b\w/g, (l) => l.toUpperCase());
-};
-
-export const PriceLevelHelper: React.FC<PriceLevelHelperProps> = ({
- transactionTotal,
-}) => {
- const {
- transactionTotalPrice,
- salesChannel,
- paymentMethodTypeToPaymentMethod,
- findBestPaymentMethod,
- } = useSalesPaymentContext();
-
- // Calculate prices and discount amounts for each payment form (using default if available, otherwise cheapest)
- const paymentPrices = useMemo(() => {
- const prices: Record<string, number> = {};
- const discounts: Record<string, number> = {};
- const defaultPaymentMethodId = salesChannel?.defaultPaymentMethodId;
-
- // Get prices for each payment form using the best method (default or cheapest)
- if (paymentMethodTypeToPaymentMethod) {
- Object.entries(paymentMethodTypeToPaymentMethod).forEach(
- ([paymentForm, paymentMethods]) => {
- if (paymentMethods && paymentMethods.length > 0) {
- const bestMethod = findBestPaymentMethod(
- paymentMethods,
- defaultPaymentMethodId,
- );
- if (bestMethod) {
- const price = transactionTotalPrice({
- paymentMethodId: bestMethod.id,
- });
- if (price !== undefined) {
- prices[paymentForm] = price;
-
- // Calculate discount amount (positive = discount, negative = surcharge)
- const discount = transactionTotal - price;
- discounts[paymentForm] = discount;
- }
- }
- }
- },
- );
- }
-
- // Check if all prices are the same
- const priceValues = Object.values(prices);
- const hasSamePrice =
- priceValues.length > 0 &&
- priceValues.every(
- (price) => Math.abs(price - (priceValues[0] ?? 0)) < 0.01,
- );
-
- return {
- prices,
- discounts,
- hasSamePrice,
- };
- }, [
- transactionTotalPrice,
- paymentMethodTypeToPaymentMethod,
- transactionTotal,
- salesChannel?.defaultPaymentMethodId,
- findBestPaymentMethod,
- ]);
-
- // If all prices are the same, return null
- if (paymentPrices.hasSamePrice) {
- return null;
- }
-
- return (
- <Collapsible>
- <CollapsibleTrigger asChild>
- <Button
- variant="ghost"
- className="w-full flex items-center justify-between p-2 text-sm font-medium text-gray-600 hover:bg-gray-50"
- >
- <div className="flex items-center gap-2">
- <Info className="w-4 h-4" />
- <span>Payment Method Discounts</span>
- </div>
- <ChevronDown className="w-4 h-4 transition-transform duration-200 group-data-[state=open]:rotate-180" />
- </Button>
- </CollapsibleTrigger>
-
- <CollapsibleContent>
- <div className="mt-3 p-3 bg-gray-50 rounded-md border border-gray-200">
- <div className="text-sm text-gray-600 mb-2 text-center">
- Below are the discounts needed to reach each payment form price
- level (using default payment method if available, otherwise cheapest
- price)
- </div>
-
- <div className="space-y-2">
- {(() => {
- // Group payment forms by discount amount
- const groupedByDiscount: Record<string, string[]> = {};
-
- Object.entries(paymentPrices.discounts).forEach(
- ([paymentForm, discount]) => {
- const discountKey = discount.toFixed(2); // Use 2 decimal places as key
- if (!groupedByDiscount[discountKey]) {
- groupedByDiscount[discountKey] = [];
- }
- groupedByDiscount[discountKey].push(paymentForm);
- },
- );
-
- // Sort discount amounts (cheapest first)
- const sortedDiscounts = Object.keys(groupedByDiscount).sort(
- (a, b) => parseFloat(a) - parseFloat(b),
- );
-
- return sortedDiscounts.map((discountKey) => {
- const discount = parseFloat(discountKey);
- const paymentForms = groupedByDiscount[discountKey];
- const isDiscount = discount > 0.01;
- const isSurcharge = discount < -0.01;
- const noChange = Math.abs(discount) < 0.01;
-
- if (!paymentForms) return null;
-
- return (
- <div
- key={discountKey}
- className="flex justify-between items-center p-2 bg-white rounded border border-gray-200"
- >
- <span className="text-sm font-medium">
- {paymentForms.map(formatPaymentMethodName).join(", ")}:
- </span>
- <span
- className={`text-sm font-semibold ${
- isDiscount
- ? "text-green-600"
- : isSurcharge
- ? "text-red-600"
- : "text-gray-600"
- }`}
- >
- {formatDiscount(discount)}
- </span>
- </div>
- );
- });
- })()}
- </div>
- </div>
- </CollapsibleContent>
- </Collapsible>
- );
-};
diff --git a/src/components/SalesScreenComponents/Modals/QuickItemEditModal.tsx b/src/components/SalesScreenComponents/Modals/QuickItemEditModal.tsx
index 6c973fd2..3b9c823f 100644
--- a/src/components/SalesScreenComponents/Modals/QuickItemEditModal.tsx
+++ b/src/components/SalesScreenComponents/Modals/QuickItemEditModal.tsx
@@ -53,7 +53,7 @@ export interface QuickItemEditModalProps {
isOpen: boolean;
onClose: () => void;
selectedCohortItemId: CohortItem["id"];
- onUpdateSuccess?: (item: EntityItemDetail) => void | Promise<void>;
+ onUpdateSuccess?: (item: EntityItemDetail) => void;
}
export const QuickItemEditModal: React.FC<QuickItemEditModalProps> = ({
@@ -82,7 +82,6 @@ export const QuickItemEditModal: React.FC<QuickItemEditModalProps> = ({
const isInactive = useMemo(
() => itemDetails?.itemTypeId === ItemTypeEnum.Inactive,
- // eslint-disable-next-line react-hooks/exhaustive-deps
[entity.id, itemDetails?.itemTypeId],
);
@@ -110,7 +109,7 @@ export const QuickItemEditModal: React.FC<QuickItemEditModalProps> = ({
});
const e = await entityItemRefetch();
if (e.data && onUpdateSuccess) {
- await onUpdateSuccess(e.data);
+ onUpdateSuccess(e.data);
}
void queryClient.invalidateQueries({
queryKey: queryKey,
diff --git a/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.stories.tsx b/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.stories.tsx
index de854558..3a181153 100644
--- a/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.stories.tsx
+++ b/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.stories.tsx
@@ -61,7 +61,7 @@ const InteractiveWrapper = (args: StoryArgs) => {
action("setHouseAccountId")(id);
}}
setHouseAccountAmount={(amt) => {
- setAmount(+amt);
+ setAmount(amt);
action("setHouseAccountAmount")(amt);
}}
setAmountChargeable={(balance) => {
diff --git a/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.tsx b/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.tsx
index e790ac22..36688344 100644
--- a/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.tsx
+++ b/src/components/SalesScreenComponents/Modals/payments/PayWithHouseAccount.tsx
@@ -10,7 +10,7 @@ import {
export type PayWithHouseAccountProps = {
loyaltyCustomerId: number;
setHouseAccountId: (houseAccountId: string) => void;
- setHouseAccountAmount: (houseAccountAmount: string) => void;
+ setHouseAccountAmount: (houseAccountAmount: number) => void;
setAmountChargeable?: (currentBalance: number | null) => void;
houseAccountId?: string;
amount: number;
@@ -94,32 +94,21 @@ export const PayWithHouseAccount = ({
value={amount}
type="number"
step={0.01}
- max={
- Math.min(maxAmount ?? Infinity, amountChargeable ?? Infinity) +
- 0.01
- }
+ max={Math.min(maxAmount ?? Infinity, amountChargeable ?? Infinity)}
onChange={(e) => {
if (e.target.value === "") {
- setHouseAccountAmount("0.00");
+ setHouseAccountAmount(0);
} else {
- setHouseAccountAmount(e.target.value);
+ setHouseAccountAmount(+e.target.value);
}
}}
/>
)}
{maxAmount && amountChargeable && !isPayingHouseAccount && (
<Button
- type="button"
- disabled={
- maxAmount.toFixed(2) == "0.00" ||
- maxAmount < 0 ||
- +amount > 0 ||
- isDisabled
- }
+ disabled={amount === maxAmount || isDisabled}
onClick={() => {
- setHouseAccountAmount(
- Math.min(maxAmount, amountChargeable).toFixed(2),
- );
+ setHouseAccountAmount(Math.min(maxAmount, amountChargeable));
}}
>
Max
diff --git a/src/components/SalesScreenComponents/SalePageConfigProvider.tsx b/src/components/SalesScreenComponents/SalePageConfigProvider.tsx
index ebbc9ff0..06d11c34 100644
--- a/src/components/SalesScreenComponents/SalePageConfigProvider.tsx
+++ b/src/components/SalesScreenComponents/SalePageConfigProvider.tsx
@@ -11,11 +11,8 @@ import {
} from "src/spring-generated";
import { SalePageConfigDispatch, store } from "src/store/salePageConfig";
import {
- overriddenCohortPriceLevelSelector,
- resetOverriddenCohortPriceLevel,
resetSalesChannel,
selectedSalesChannelSelector,
- selectOverriddenCohortPriceLevel,
selectSalesChannel,
setInStoreSalesChannel,
} from "src/store/salePageConfig/salePageConfigSlice";
@@ -69,9 +66,6 @@ const SalePageConfigLoader: React.FC<{ children: React.ReactNode }> = ({
export const useSalePageConfig = () => {
const dispatch = useDispatch<SalePageConfigDispatch>();
const selectedSalesChannel = useSelector(selectedSalesChannelSelector);
- const overriddenCohortPriceLevel = useSelector(
- overriddenCohortPriceLevelSelector,
- );
const queryClient = useQueryClient();
if (!selectedSalesChannel) {
@@ -96,23 +90,9 @@ export const useSalePageConfig = () => {
dispatch(resetSalesChannel());
}, [dispatch]);
- const selectOverriddenCohortPriceLevelCallback = useCallback(
- (priceLevelId: number | undefined) => {
- dispatch(selectOverriddenCohortPriceLevel(priceLevelId));
- },
- [dispatch],
- );
-
- const resetOverriddenCohortPriceLevelCallback = useCallback(() => {
- dispatch(resetOverriddenCohortPriceLevel());
- }, [dispatch]);
-
return {
selectedSalesChannel,
selectSalesChannel: selectSalesChannelCallback,
resetSalesChannel: resetSalesChannelCallback,
- overriddenCohortPriceLevel,
- selectOverriddenCohortPriceLevel: selectOverriddenCohortPriceLevelCallback,
- resetOverriddenCohortPriceLevel: resetOverriddenCohortPriceLevelCallback,
};
};
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/CashOptions/CashOptions.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/CashOptions/CashOptions.tsx
index 5b4082a9..7936485f 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/CashOptions/CashOptions.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/CashOptions/CashOptions.tsx
@@ -1,12 +1,9 @@
import { isNotInStoreChannel } from "components/payment/disablePaymentMethods";
import { ButtonSize } from "components/ui/button";
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "components/ui/tabs";
import { shadcnResponsiveButtonSizes } from "config/styles/button";
import { useEntitySelected } from "context/EntityProvider";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { TransactionPaymentForm } from "generated/types";
-import { useCallback, useEffect, useState } from "react";
-import { formatPrice } from "utils/currencyUtils";
import { SalesButtonGroup } from "../SalesButtonGroup";
export interface CashOptionsProps {
@@ -29,188 +26,67 @@ export const CashOptions: React.FC<CashOptionsProps> = ({
isPersisting,
isCalculatingCartPrice,
salesChannel,
- setSelectedCashPaymentMethodId,
- calculateMethodsWithPrices,
} = useSalesPaymentContext();
-
const notInStoreChannel = isNotInStoreChannel({
salesChannelTypeId: salesChannel.salesChannelTypeId,
cohortId: entity.cohortId,
});
-
- // Get deduplicated cash methods
- const methodsWithPrices = calculateMethodsWithPrices(
- TransactionPaymentForm.CASH,
- );
- const cashMethods = methodsWithPrices.map(({ method }) => method);
-
- // State for selected cash method
- const [selectedCashMethod, setSelectedCashMethod] = useState<
- string | undefined
- >(cashMethods.length > 0 ? cashMethods[0]?.id : undefined);
-
- // Get cash total for the selected method
- // If no methods available (fallback context), use default total
- const cashTotal =
- methodsWithPrices.length > 0
- ? transactionTotalPrice({ paymentMethodId: selectedCashMethod })
- : transactionTotalPrice();
-
- // Update the global payment method ID when the selected tab changes
- useEffect(() => {
- if (
- selectedCashMethod &&
- amountReceived?.paymentForm === TransactionPaymentForm.CASH
- ) {
- setAmountPaid((prev) => {
- if (!prev) return prev;
- return {
- ...prev,
- paymentMethodId: selectedCashMethod,
- };
- });
- }
- }, [selectedCashMethod, amountReceived?.paymentForm, setAmountPaid]);
-
- // Helper function to create money denomination buttons for a specific method
- const createMoneyButtons = useCallback(
- (
- methodId: string | undefined,
- methodTotal: number,
- testIdPrefix: string = "",
- ) => {
- return [
- "$5",
- "$10",
- "$20",
- "$25",
- "$50",
- "$100",
- `$${(methodTotal - (amountReceived?.amountPaid ?? 0)).toFixed(2)}`,
- `$${Math.ceil(methodTotal - (amountReceived?.amountPaid ?? 0)).toFixed(2)}`,
- ].map((money, i) => ({
- size: buttonSize ?? shadcnResponsiveButtonSizes,
- disabled:
- !transactionItems.length ||
- transactionTotalPrice() < 0 ||
- isPersisting ||
- isCalculatingCartPrice ||
- notInStoreChannel,
- requires: "payment_option/cash:use",
- "data-testid": `moneys-${testIdPrefix}${i}`,
- onClick: () => {
- setAmountPaid((prev) => {
- const newAmountPaid =
- (prev?.amountPaid ?? 0) + +money.replaceAll("$", "");
- return {
- ...prev,
- amountPaid: newAmountPaid,
- paymentForm: TransactionPaymentForm.CASH,
- paymentMethodId: methodId || prev?.paymentMethodId,
- };
- });
- },
- label: money,
- }));
- },
- [
- buttonSize,
- transactionItems.length,
- transactionTotalPrice,
- isPersisting,
- isCalculatingCartPrice,
- notInStoreChannel,
- amountReceived?.amountPaid,
- setAmountPaid,
- ],
- );
-
- if (cashTotal === undefined) {
- return null;
- }
-
- // Helper function to create the "Enter $" button
- const createEnterButton = (methodId?: string) => ({
- label: "Enter $ (F2)",
- requires: "payment_option/cash:use",
- disabled:
- !transactionItems.length ||
- isPersisting ||
- isCalculatingCartPrice ||
- notInStoreChannel,
- onClick: () => {
- setSelectedCashPaymentMethodId(methodId);
- openPaymentModal();
- },
- size: buttonSize ?? shadcnResponsiveButtonSizes,
- "data-testid": `enter-custom-amount-btn${methodId ? `-${methodId}` : ""}`,
+ const MONEYS = [
+ "$5",
+ "$10",
+ "$20",
+ "$25",
+ "$50",
+ "$100",
+ `$${(transactionTotalPrice() - (amountReceived?.amountPaid ?? 0)).toFixed(2)}`,
+ `$${Math.ceil(transactionTotalPrice() - (amountReceived?.amountPaid ?? 0)).toFixed(2)}`,
+ ].map((money, i) => {
+ return {
+ size: buttonSize ?? shadcnResponsiveButtonSizes,
+ disabled:
+ !transactionItems.length ||
+ transactionTotalPrice() < 0 ||
+ isPersisting ||
+ isCalculatingCartPrice ||
+ notInStoreChannel,
+ requires: "payment_option/cash:use",
+ "data-testid": `moneys-${i}`,
+ onClick: () => {
+ setAmountPaid((prev) => {
+ const newAmountPaid =
+ (prev?.amountPaid ?? 0) + +money.replaceAll("$", "");
+ return {
+ ...prev,
+ amountPaid: newAmountPaid,
+ paymentForm: TransactionPaymentForm.CASH,
+ };
+ });
+ },
+ label: money,
+ };
});
- // Helper function to render cash content for a method
- const renderCashContent = (
- methodId: string | undefined,
- methodTotal: number,
- testIdPrefix: string = "",
- ) => (
- <>
- <div className="text-lg font-semibold text-green-700 mb-3 text-center">
- Cash Total: {formatPrice(methodTotal)}
- </div>
- <SalesButtonGroup
- colorScheme="green"
- wrapProps={{ justifyContent: justifyButtons }}
- elements={[
- ...createMoneyButtons(methodId, methodTotal, testIdPrefix),
- createEnterButton(methodId),
- ]}
- />
- </>
- );
-
- // If no total, return null
- if (cashTotal === undefined) {
- return null;
- }
-
- // If no cash methods (fallback context), show simple version with default total
- if (methodsWithPrices.length === 0) {
- return renderCashContent(undefined, cashTotal);
- }
-
- // If only one cash method, show the simple version without tabs
- if (methodsWithPrices.length === 1) {
- return renderCashContent(selectedCashMethod, cashTotal);
- }
-
- // Multiple cash methods - show tabs
return (
- <Tabs
- value={selectedCashMethod}
- onValueChange={setSelectedCashMethod}
- className="w-full"
- >
- <TabsList
- className="grid w-full mb-4"
- style={{
- gridTemplateColumns: `repeat(${methodsWithPrices.length}, 1fr)`,
- }}
- >
- {methodsWithPrices.map(({ method, total }) => {
- return (
- <TabsTrigger key={method.id} value={method.id} className="text-sm">
- {method.paymentMethodType} ({formatPrice(total || 0)})
- </TabsTrigger>
- );
- })}
- </TabsList>
-
- {methodsWithPrices.map(({ method, total }) => {
- return (
- <TabsContent key={method.id} value={method.id} className="mt-0">
- {renderCashContent(method.id, total || 0, `${method.id}-`)}
- </TabsContent>
- );
- })}
- </Tabs>
+ <SalesButtonGroup
+ colorScheme="green"
+ wrapProps={{ justifyContent: justifyButtons }}
+ elements={[
+ ...MONEYS,
+ {
+ label: "Enter $ (F2)",
+ requires: "payment_option/cash:use",
+ disabled:
+ !transactionItems.length ||
+ isPersisting ||
+ isCalculatingCartPrice ||
+ notInStoreChannel,
+ onClick: () => {
+ openPaymentModal();
+ },
+ size: buttonSize ?? shadcnResponsiveButtonSizes,
+ "data-testid": "enter-custom-amount-btn",
+ },
+ ]}
+ />
);
};
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/Miscellaneous/Miscellaneous.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/Miscellaneous/Miscellaneous.tsx
index 79d3c368..4c6b8d3f 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/Miscellaneous/Miscellaneous.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/Miscellaneous/Miscellaneous.tsx
@@ -1,23 +1,23 @@
import { CheckCircleIcon, DeleteIcon } from "@chakra-ui/icons";
import {
- FormControl,
- FormLabel,
- HStack,
- Text,
- useDisclosure,
- useToast,
+ FormControl,
+ FormLabel,
+ HStack,
+ Text,
+ useDisclosure,
+ useToast,
} from "@chakra-ui/react";
import PayoutModal from "components/payout/PayoutModal";
import { captureException } from "config/sentry/TransformitySentry";
import {
- responsiveButtonSizes,
- shadcnResponsiveButtonSizes,
+ responsiveButtonSizes,
+ shadcnResponsiveButtonSizes,
} from "config/styles/button";
import { useAuthorization } from "context/AuthorizationContext/useAuthorizationContext";
import { useSalesContext } from "context/Sales/SalesContext";
import {
- customerDiscount,
- customerTaxExempt,
+ customerDiscount,
+ customerTaxExempt,
} from "context/Sales/SalesContextProvider";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { format } from "date-fns";
@@ -29,15 +29,15 @@ import { FaPeopleGroup } from "react-icons/fa6";
import { MdDiscount, MdOutlinePayments } from "react-icons/md";
import { CustomerLookupModal } from "src/components/loyalty/CustomerLookupModal/CustomerLookupModal";
import {
- useEntitySelected,
- useLoyaltyProgramIdOptional,
+ useEntitySelected,
+ useLoyaltyProgramIdOptional,
} from "src/context/EntityProvider";
import {
- CartDiscountType,
- LoyaltyCustomer,
- LoyaltyCustomerProfile,
- PaymentProcessorType,
- useCancelTransaction,
+ CartDiscountType,
+ LoyaltyCustomer,
+ LoyaltyCustomerProfile,
+ PaymentProcessorType,
+ useCancelTransaction,
} from "src/generated";
import { TransformitySwitch } from "../../../common/Switch/TransformitySwitch";
import { CartHoldsModal } from "../../Modals/CartHoldsModal";
@@ -47,32 +47,32 @@ import { SalesButtonGroup, SalesButtonGroupElement } from "../SalesButtonGroup";
export interface MiscellaneousProps {}
export const Miscellaneous: React.FC<MiscellaneousProps> = () => {
- const toast = useToast();
- const {
- discount,
- customer,
- items: itemDetails = new Map<number, LineItem>(),
- taxExempt,
- setDeviceBusy,
- selectedItems,
- transactionId,
- setTransactionId,
- clearCart,
- calculateCartPrice,
- } = useSalesContext();
- const { overrideLogout } = useAuthorization();
- const { governmentID, customerLookupModal } = useSalesPaymentContext();
- const { id } = useLoyaltyProgramIdOptional();
- const [entity] = useEntitySelected();
- const [action, setAction] = useState("PAYOUT");
+ const toast = useToast();
+ const {
+ discount,
+ customer,
+ items: itemDetails = new Map<number, LineItem>(),
+ taxExempt,
+ setDeviceBusy,
+ selectedItems,
+ transactionId,
+ setTransactionId,
+ clearCart,
+ calculateCartPrice,
+ } = useSalesContext();
+ const { overrideLogout } = useAuthorization();
+ const { governmentID, customerLookupModal } = useSalesPaymentContext();
+ const { id } = useLoyaltyProgramIdOptional();
+ const [entity] = useEntitySelected();
+ const [action, setAction] = useState("PAYOUT");
- // discount should be updated after modal is closed
- const { isOpen, onOpen, onClose } = useDisclosure();
- const cartHoldsDisclosure = useDisclosure();
- const payoutDisclosure = useDisclosure();
- const { mutateAsync: cancelTransaction, isPending } = useCancelTransaction(
- transactionId ?? 0,
- );
+ // discount should be updated after modal is closed
+ const { isOpen, onOpen, onClose } = useDisclosure();
+ const cartHoldsDisclosure = useDisclosure();
+ const payoutDisclosure = useDisclosure();
+ const { mutateAsync: cancelTransaction, isPending } = useCancelTransaction(
+ transactionId ?? 0,
+ );
const elements: SalesButtonGroupElement[] = useMemo(() => {
const discountPermission =
@@ -194,170 +194,167 @@ export const Miscellaneous: React.FC<MiscellaneousProps> = () => {
calculateCartPrice,
]);
- const applyCustomerDiscountsToCart = async (
- customer: LoyaltyCustomer | LoyaltyCustomerProfile,
- ) => {
- // Convert LoyaltyCustomerProfile to LoyaltyCustomer format for cart calculations if needed
- const customerForCart: LoyaltyCustomer =
- "loyaltyCustomerId" in customer
- ? {
- ...customer,
- id: customer.id,
- loyaltyCustomerId: customer.loyaltyCustomerId,
- customerId: customer.customerId,
- isEmployee: customer.isEmployee ?? false,
- }
- : customer;
+ const applyCustomerDiscountsToCart = async (
+ customer: LoyaltyCustomer | LoyaltyCustomerProfile,
+ ) => {
+ // Convert LoyaltyCustomerProfile to LoyaltyCustomer format for cart calculations if needed
+ const customerForCart: LoyaltyCustomer =
+ "loyaltyCustomerId" in customer
+ ? {
+ ...customer,
+ id: customer.id,
+ loyaltyCustomerId: customer.loyaltyCustomerId,
+ customerId: customer.customerId,
+ isEmployee: customer.isEmployee ?? false,
+ }
+ : customer;
- try {
- await calculateCartPrice({
- requestedItems: new Map(
- [...itemDetails.entries()].map(([id, prevItem]) => {
- const isPriceAtCost = customerForCart?.priceAtCost;
- if (isPriceAtCost) {
- const cost = prevItem.item?.ei_cost
- ? Number(prevItem.item.ei_cost)
- : undefined;
- prevItem.price = cost ?? prevItem.price;
- } else if (isNil(isPriceAtCost)) {
- prevItem.price = prevItem.originalPrice ?? prevItem.price;
- }
+ try {
+ await calculateCartPrice({
+ requestedItems: new Map(
+ [...itemDetails.entries()].map(([id, prevItem]) => {
+ const isPriceAtCost = customerForCart?.priceAtCost;
+ if (isPriceAtCost) {
+ prevItem.price = prevItem.item?.cost ?? prevItem.price;
+ } else if (isNil(isPriceAtCost)) {
+ prevItem.price = prevItem.originalPrice ?? prevItem.price;
+ }
- const lineItemDiscount = customerForCart?.lineItemFixedDiscount;
- const lineItemDiscountPercent = lineItemDiscount
- ? lineItemDiscount * 100
- : undefined;
- prevItem.lineItemDiscount = lineItemDiscountPercent
- ? {
- type: CartDiscountType.PERCENT,
- value: lineItemDiscountPercent,
- }
- : undefined;
+ const lineItemDiscount = customerForCart?.lineItemFixedDiscount;
+ const lineItemDiscountPercent = lineItemDiscount
+ ? lineItemDiscount * 100
+ : undefined;
+ prevItem.lineItemDiscount = lineItemDiscountPercent
+ ? {
+ type: CartDiscountType.PERCENT,
+ value: lineItemDiscountPercent,
+ }
+ : undefined;
- return [id, prevItem];
- }),
- ),
- requestedCustomer: customerForCart,
- requestTaxExempt: customerTaxExempt(customerForCart),
- requestedDiscount: !customerForCart?.lineItemFixedDiscount
- ? customerDiscount(customerForCart)
- : undefined,
- });
- } catch {
- // no need to do anything since the error is handled in calculateCartPrice
- }
- };
+ return [id, prevItem];
+ }),
+ ),
+ requestedCustomer: customerForCart,
+ requestTaxExempt: customerTaxExempt(customerForCart),
+ requestedDiscount: !customerForCart?.lineItemFixedDiscount
+ ? customerDiscount(customerForCart)
+ : undefined,
+ });
+ } catch {
+ // no need to do anything since the error is handled in calculateCartPrice
+ }
+ };
- const updateCartWithCustomerDiscounts = async (
- updatedCustomer: LoyaltyCustomerProfile,
- ) => {
- await applyCustomerDiscountsToCart(updatedCustomer);
- };
+ const updateCartWithCustomerDiscounts = async (
+ updatedCustomer: LoyaltyCustomerProfile,
+ ) => {
+ await applyCustomerDiscountsToCart(updatedCustomer);
+ };
- return (
- <>
- <SalesButtonGroup
- elements={elements}
- colorScheme="red"
- wrapItemProps={{ alignItems: "center" }}
- />
- <DiscountModal
- isOpen={isOpen}
- onClose={onClose}
- setDiscountValue={async (discountVal) => {
- if (selectedItems.size > 0) {
- try {
- await calculateCartPrice({
- requestedItems: new Map(
- [...itemDetails.values()].map((prevItem) => {
- if (selectedItems.has(prevItem.id)) {
- prevItem.lineItemDiscount = discountVal;
- }
- return [prevItem.id, prevItem];
- }),
- ),
- requestedCustomer: customer,
- requestTaxExempt: taxExempt,
- requestedDiscount: discount,
- });
- } catch (e) {
- // no need to do anything since the error is handled in calculateCartPrice
- }
- } else {
- try {
- await calculateCartPrice({
- requestedItems: itemDetails,
- requestedCustomer: customer,
- requestTaxExempt: taxExempt,
- requestedDiscount: discountVal,
- });
- } catch (e) {
- // no need to do anything since the error is handled in calculateCartPrice
- }
- }
- }}
- discountValue={discount}
- />
- <CartHoldsModal
- isOpen={cartHoldsDisclosure.isOpen}
- onClose={cartHoldsDisclosure.onClose}
- />
- <CustomerLookupModal
- defaultValues={
- governmentID
- ? {
- birthDate: governmentID.birthdate
- ? format(governmentID.birthdate, "MMddyyyy")
- : undefined,
- ...governmentID,
- }
- : undefined
- }
- disclosure={customerLookupModal}
- setCustomer={async (customer) => {
- if (customer) {
- await applyCustomerDiscountsToCart(customer);
- } else {
- // When customer is undefined (unlinked), recalculate cart without customer discounts
- try {
- await calculateCartPrice({
- requestedItems: new Map(
- [...itemDetails.entries()].map(([id, prevItem]) => {
- // Reset to original price when customer is unlinked
- prevItem.price = prevItem.originalPrice ?? prevItem.price;
- // Remove line item discounts
- prevItem.lineItemDiscount = undefined;
- return [id, prevItem];
- }),
- ),
- requestedCustomer: undefined,
- requestTaxExempt: false,
- requestedDiscount: undefined,
- });
- } catch {
- // no need to do anything since the error is handled in calculateCartPrice
- }
- }
- }}
- linkedCustomer={customer}
- onCustomerUpdated={updateCartWithCustomerDiscounts}
- allowDeviceActions={
- entity.paymentProcessor?.processorName === PaymentProcessorType.stripe
- }
- setDeviceBusy={setDeviceBusy}
- />
- <PayoutModal
- {...payoutDisclosure}
- onClose={() => {
- setAction("PAYOUT");
- payoutDisclosure.onClose();
- }}
- action={action}
- setAction={setAction}
- onSubmit={(data: any) => {
- console.log(data);
- }}
- />
- </>
- );
+ return (
+ <>
+ <SalesButtonGroup
+ elements={elements}
+ colorScheme="red"
+ wrapItemProps={{ alignItems: "center" }}
+ />
+ <DiscountModal
+ isOpen={isOpen}
+ onClose={onClose}
+ setDiscountValue={async (discountVal) => {
+ if (selectedItems.size > 0) {
+ try {
+ await calculateCartPrice({
+ requestedItems: new Map(
+ [...itemDetails.values()].map((prevItem) => {
+ if (selectedItems.has(prevItem.id)) {
+ prevItem.lineItemDiscount = discountVal;
+ }
+ return [prevItem.id, prevItem];
+ }),
+ ),
+ requestedCustomer: customer,
+ requestTaxExempt: taxExempt,
+ requestedDiscount: discount,
+ });
+ } catch (e) {
+ // no need to do anything since the error is handled in calculateCartPrice
+ }
+ } else {
+ try {
+ await calculateCartPrice({
+ requestedItems: itemDetails,
+ requestedCustomer: customer,
+ requestTaxExempt: taxExempt,
+ requestedDiscount: discountVal,
+ });
+ } catch (e) {
+ // no need to do anything since the error is handled in calculateCartPrice
+ }
+ }
+ }}
+ discountValue={discount}
+ />
+ <CartHoldsModal
+ isOpen={cartHoldsDisclosure.isOpen}
+ onClose={cartHoldsDisclosure.onClose}
+ />
+ <CustomerLookupModal
+ defaultValues={
+ governmentID
+ ? {
+ birthDate: governmentID.birthdate
+ ? format(governmentID.birthdate, "MMddyyyy")
+ : undefined,
+ ...governmentID,
+ }
+ : undefined
+ }
+ disclosure={customerLookupModal}
+ setCustomer={async (customer) => {
+ if (customer) {
+ await applyCustomerDiscountsToCart(customer);
+ } else {
+ // When customer is undefined (unlinked), recalculate cart without customer discounts
+ try {
+ await calculateCartPrice({
+ requestedItems: new Map(
+ [...itemDetails.entries()].map(([id, prevItem]) => {
+ // Reset to original price when customer is unlinked
+ prevItem.price = prevItem.originalPrice ?? prevItem.price;
+ // Remove line item discounts
+ prevItem.lineItemDiscount = undefined;
+ return [id, prevItem];
+ }),
+ ),
+ requestedCustomer: undefined,
+ requestTaxExempt: false,
+ requestedDiscount: undefined,
+ });
+ } catch {
+ // no need to do anything since the error is handled in calculateCartPrice
+ }
+ }
+ }}
+ linkedCustomer={customer}
+ onCustomerUpdated={updateCartWithCustomerDiscounts}
+ allowDeviceActions={
+ entity.paymentProcessor?.processorName === PaymentProcessorType.stripe
+ }
+ setDeviceBusy={setDeviceBusy}
+ />
+ <PayoutModal
+ {...payoutDisclosure}
+ onClose={() => {
+ setAction("PAYOUT");
+ payoutDisclosure.onClose();
+ }}
+ action={action}
+ setAction={setAction}
+ onSubmit={(data: any) => {
+ console.log(data);
+ }}
+ />
+ </>
+ );
};
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/CreditCardOptions.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/CreditCardOptions.tsx
deleted file mode 100644
index f3e97c66..00000000
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/CreditCardOptions.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { isNotInStoreChannel } from "components/payment/disablePaymentMethods";
-import { ButtonSize } from "components/ui/button";
-import { shadcnResponsiveButtonSizes } from "config/styles/button";
-import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
-import { TransactionPaymentForm } from "generated/types";
-import { FaCreditCard } from "react-icons/fa";
-import { useEntitySelected } from "src/context/EntityProvider";
-import { formatPrice } from "utils/currencyUtils";
-import { SalesButton } from "../SalesButtonGroup";
-
-export interface CreditCardOptionsProps {
- buttonSize?: ButtonSize | ButtonSize[];
- onSubmit?: () => void;
-}
-
-export const CreditCardOptions = ({
- buttonSize,
- onSubmit,
-}: CreditCardOptionsProps): SalesButton[] => {
- const [entity] = useEntitySelected();
- const {
- transactionItems,
- transactionTotalPrice,
- creditCardPaid,
- creditCardModalV2,
- reviewTransactionModal,
- isPersisting,
- isCalculatingCartPrice,
- salesChannel,
- paymentMethodTypeToPaymentMethod,
- calculateMethodsWithPrices,
- } = useSalesPaymentContext();
-
- const notInStoreChannel = isNotInStoreChannel({
- salesChannelTypeId: salesChannel.salesChannelTypeId,
- cohortId: entity.cohortId,
- });
- const creditCardMethods =
- paymentMethodTypeToPaymentMethod[TransactionPaymentForm["CREDIT CARD"]] ||
- [];
-
- const handleCreditCardClick =
- (paymentMethodId?: string) => (e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- (e.currentTarget as HTMLButtonElement).blur();
- creditCardPaid(undefined, paymentMethodId);
- creditCardModalV2.onOpen();
- reviewTransactionModal.onClose();
- onSubmit?.();
- };
-
- // Create buttons for each credit card method, deduplicating by total price
- const methodsWithPrices = calculateMethodsWithPrices(
- TransactionPaymentForm["CREDIT CARD"],
- );
- const creditCardButtons: SalesButton[] = methodsWithPrices.map(
- ({ method, total }) => {
- const label = `Credit (${formatPrice(total)})`;
-
- const isDisabled =
- !transactionItems.length ||
- !entity.creditCardMerchantId ||
- isPersisting ||
- total === undefined ||
- total <= 0 ||
- isCalculatingCartPrice ||
- notInStoreChannel;
-
- return {
- label,
- leftIcon: <FaCreditCard />,
- requires: "payment_option/credit_card:use",
- size: buttonSize ?? shadcnResponsiveButtonSizes,
- disabled: isDisabled,
- onClick: handleCreditCardClick(method.id),
- } as SalesButton;
- },
- );
-
- // If no specific methods, return the default credit card button
- if (creditCardButtons.length === 0) {
- const defaultTotal = transactionTotalPrice();
- const defaultLabel = `Credit (F8) (${formatPrice(defaultTotal)})`;
-
- const isDisabled =
- !transactionItems.length ||
- !entity.creditCardMerchantId ||
- isPersisting ||
- defaultTotal === undefined ||
- defaultTotal <= 0 ||
- isCalculatingCartPrice ||
- notInStoreChannel;
-
- return [
- {
- label: defaultLabel,
- leftIcon: <FaCreditCard />,
- requires: "payment_option/credit_card:use",
- size: buttonSize ?? shadcnResponsiveButtonSizes,
- disabled: isDisabled,
- onClick: handleCreditCardClick(),
- } as SalesButton,
- ];
- }
-
- return creditCardButtons;
-};
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/GiftCards/GiftCardSaleModal.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/GiftCards/GiftCardSaleModal.tsx
index d9041b9a..e70b6711 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/GiftCards/GiftCardSaleModal.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/GiftCards/GiftCardSaleModal.tsx
@@ -30,7 +30,6 @@ export type GiftCardSaleModalProps = {
isOpen: boolean;
onClose: () => void;
onClick: (giftCard: GiftCardSaleFormProps) => void;
- paymentMethodId?: string;
};
export function currGiftCardBalance(currGiftCard?: GiftCard | null) {
@@ -50,7 +49,6 @@ export const GiftCardSaleModal = ({
isOpen,
onClose,
onClick,
- paymentMethodId,
}: GiftCardSaleModalProps) => {
const {
handleSubmit,
@@ -138,8 +136,7 @@ export const GiftCardSaleModal = ({
isDisabled={
isValid &&
(currGiftCard?.balance ?? 0) !== 0 &&
- (currGiftCard?.balance ?? 0) >
- transactionTotalPrice({ paymentMethodId })
+ (currGiftCard?.balance ?? 0) > transactionTotalPrice()
}
label={
"Gift Card is not valid or does not have sufficient balance."
@@ -151,8 +148,7 @@ export const GiftCardSaleModal = ({
isDisabled={
!isValid ||
(currGiftCard?.balance ?? 0) === 0 ||
- (currGiftCard?.balance ?? 0) <
- transactionTotalPrice({ paymentMethodId })
+ (currGiftCard?.balance ?? 0) < transactionTotalPrice()
}
type="submit"
>
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/HouseAccountPaymentModal.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/HouseAccountPaymentModal.tsx
index f3878d30..95d0401d 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/HouseAccountPaymentModal.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/HouseAccountPaymentModal.tsx
@@ -10,12 +10,11 @@ import { CustomerEditModal } from "../../../../loyalty/CustomerProfile/CustomerE
type HouseAccountPaymentModalProps = {
isOpen: boolean;
onClose: () => void;
- paymentMethodId?: string;
};
export const HouseAccountPaymentModal: React.FC<
HouseAccountPaymentModalProps
-> = ({ isOpen, onClose, paymentMethodId }) => {
+> = ({ isOpen, onClose }) => {
const {
customer,
setAmountPaid,
@@ -52,14 +51,11 @@ export const HouseAccountPaymentModal: React.FC<
amountPaid: 0,
houseAccountId,
paymentForm: TransactionPaymentForm["HOUSE ACCOUNT"],
- paymentMethodId,
}));
},
- [setAmountPaid, paymentMethodId],
+ [setAmountPaid],
);
- const houseAccountAmount = transactionTotalPrice({ paymentMethodId });
-
return (
<>
<BasicModal
@@ -84,19 +80,18 @@ export const HouseAccountPaymentModal: React.FC<
}))
}
houseAccountId={amountReceived?.houseAccountId}
- amount={houseAccountAmount}
+ amount={transactionTotalPrice()}
showAmount={false}
onTriggerCreateHouseAccount={handleTriggerCreateHouseAccount}
/>
<div className="flex flex-row justify-end gap-2">
<Button
- disabled={houseAccountAmount > (amountChargeable ?? 0)}
+ disabled={transactionTotalPrice() > (amountChargeable ?? 0)}
onClick={() => {
setAmountPaid((prev) => ({
...prev,
paymentForm: TransactionPaymentForm["HOUSE ACCOUNT"],
- paymentMethodId,
- houseAccountAmount: houseAccountAmount,
+ houseAccountAmount: transactionTotalPrice(),
amountPaid: 0,
}));
onClose();
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.test.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.test.tsx
deleted file mode 100644
index 2090633c..00000000
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.test.tsx
+++ /dev/null
@@ -1,376 +0,0 @@
-import { useDisclosure } from "@chakra-ui/react";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { fireEvent, render, screen } from "@testing-library/react";
-import { TransactionPaymentForm } from "src/generated";
-import {
- createMockSalesContext,
- createMockSalesPaymentContext,
-} from "src/test-utils";
-import { MockEntityProvider } from "src/test/mocks/entityProvider";
-import { beforeEach, describe, expect, it, vi } from "vitest";
-import { OtherOptionsModal, OtherOptionsModalType } from "./OtherOptionsModal";
-
-// Create mocks using the consolidated functions
-const mockSalesContext = createMockSalesContext({
- paymentMethodTypeToPaymentMethod: {
- [TransactionPaymentForm.CASH]: [{ id: "cash-1", name: "Cash" }],
- [TransactionPaymentForm["CREDIT CARD"]]: [
- { id: "cc-1", name: "Credit Card" },
- ],
- [TransactionPaymentForm.CHECK]: [{ id: "check-1", name: "Check" }],
- [TransactionPaymentForm["GIFT CARD"]]: [
- { id: "gift-1", name: "Gift Card" },
- ],
- [TransactionPaymentForm.LATER]: [{ id: "later-1", name: "Pay Later" }],
- [TransactionPaymentForm.OTHER]: [{ id: "other-1", name: "Other" }],
- [TransactionPaymentForm.POINTS]: [{ id: "points-1", name: "Points" }],
- [TransactionPaymentForm["HOUSE ACCOUNT"]]: [
- { id: "house-1", name: "House Account" },
- ],
- },
-});
-const mockSalesPaymentContext = createMockSalesPaymentContext({
- salesChannel: { salesChannelTypeId: 1, defaultPaymentMethodId: "cash-1" }, // In-store channel
-});
-
-// Mock the SalesContext
-vi.mock("src/context/Sales/SalesContext", () => ({
- useSalesContext: () => mockSalesContext,
-}));
-
-// Mock the SalesPaymentContext
-vi.mock("src/context/Sales/SalesPaymentContext", () => ({
- useSalesPaymentContext: () => mockSalesPaymentContext,
-}));
-
-// Mock the ManualCardPunchModal
-vi.mock(
- "src/components/SalesScreenComponents/Modals/ManualCardPunchModal",
- () => ({
- ManualCardPunchModal: ({ isOpen, onClose, onSubmit }: any) => (
- <div data-testid="manual-card-punch-modal">
- {isOpen && (
- <div>
- <button onClick={onClose} data-testid="manual-modal-close">
- Close
- </button>
- <button onClick={onSubmit} data-testid="manual-modal-submit">
- Submit
- </button>
- </div>
- )}
- </div>
- ),
- }),
-);
-
-// Test wrapper component
-const TestWrapper = ({ children }: { children: React.ReactNode }) => {
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: { retry: false },
- mutations: { retry: false },
- },
- });
-
- return (
- <QueryClientProvider client={queryClient}>
- <MockEntityProvider>{children}</MockEntityProvider>
- </QueryClientProvider>
- );
-};
-
-// Helper component to test the modal
-const TestOtherOptionsModal = (props: Partial<OtherOptionsModalType>) => {
- const disclosure = useDisclosure({ isOpen: true });
- const giftCardDisclosure = useDisclosure();
- const houseAccountDisclosure = useDisclosure();
-
- return (
- <OtherOptionsModal
- disclosure={disclosure}
- giftCardDisclosure={giftCardDisclosure}
- houseAccountDisclosure={houseAccountDisclosure}
- setSelectedHouseAccountPaymentMethodId={vi.fn()}
- setSelectedGiftCardPaymentMethodId={vi.fn()}
- {...props}
- />
- );
-};
-
-describe("OtherOptionsModal", () => {
- beforeEach(() => {
- vi.clearAllMocks();
- });
-
- it("renders the modal with payment options", () => {
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- expect(screen.getByText("Payment Options")).toBeInTheDocument();
- expect(screen.getByText("Check")).toBeInTheDocument();
- expect(screen.getByText("Gift Card")).toBeInTheDocument();
- // Pay Later button may not be rendered if no payment methods are available
- const payLaterButton = screen.queryByText("Pay Later");
- // If it exists, it should be in the document
- if (payLaterButton) {
- expect(payLaterButton).toBeInTheDocument();
- }
- expect(screen.getByText("Manual Card")).toBeInTheDocument();
- expect(screen.getByText("Other/External")).toBeInTheDocument();
- // Points button may not be rendered if no payment methods are available
- const pointsButton = screen.queryByText("Points");
- // If it exists, it should be in the document
- if (pointsButton) {
- expect(pointsButton).toBeInTheDocument();
- }
- expect(screen.getByText("House Account")).toBeInTheDocument();
- });
-
- it("calls transactionTotalPrice when calculating payment amounts", () => {
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- // The component should call transactionTotalPrice during rendering to determine button states
- expect(mockSalesPaymentContext.transactionTotalPrice).toHaveBeenCalled();
- });
-
- it("uses correct transaction total price for Check payment", () => {
- // Set up a specific return value to test
- mockSalesPaymentContext.transactionTotalPrice.mockReturnValue(40);
-
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- const checkButton = screen.getByText("Check");
-
- // Only click if the button is not disabled
- if (!checkButton.hasAttribute("disabled")) {
- fireEvent.click(checkButton);
-
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith({
- amountPaid: 0,
- checkAmountReceived: 40,
- paymentForm: TransactionPaymentForm.CHECK,
- });
- }
- });
-
- it("uses correct transaction total price for Other payment", () => {
- // Set up a specific return value to test
- mockSalesPaymentContext.transactionTotalPrice.mockReturnValue(40);
-
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- const otherButton = screen.getByText("Other/External");
-
- // Only click if the button is not disabled
- if (!otherButton.hasAttribute("disabled")) {
- fireEvent.click(otherButton);
-
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith({
- amountPaid: 0,
- otherAmountReceived: 40,
- paymentForm: TransactionPaymentForm.OTHER,
- });
- }
- });
-
- it("sets correct payment form for Pay Later", () => {
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- const payLaterButton = screen.getByTestId("other-options-pay-later-btn");
-
- // Only click if the button is not disabled
- if (!payLaterButton.hasAttribute("disabled")) {
- fireEvent.click(payLaterButton);
-
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith({
- amountPaid: 0,
- otherAmountReceived: 0,
- checkAmountReceived: 0,
- creditCardAmountReceived: 0,
- paymentForm: TransactionPaymentForm.LATER,
- });
- }
- });
-
- it("opens gift card modal when Gift Card is clicked", () => {
- const giftCardDisclosure = {
- onOpen: vi.fn(),
- onClose: vi.fn(),
- onToggle: vi.fn(),
- isOpen: false,
- isControlled: false,
- getButtonProps: vi.fn(() => ({})),
- getDisclosureProps: vi.fn(() => ({})),
- };
-
- render(
- <TestWrapper>
- <TestOtherOptionsModal giftCardDisclosure={giftCardDisclosure} />
- </TestWrapper>,
- );
-
- const giftCardButton = screen.getByText("Gift Card");
-
- // Only click if the button is not disabled
- if (!giftCardButton.hasAttribute("disabled")) {
- fireEvent.click(giftCardButton);
- expect(giftCardDisclosure.onOpen).toHaveBeenCalled();
- }
- });
-
- it("opens house account modal when House Account is clicked", () => {
- const houseAccountDisclosure = {
- onOpen: vi.fn(),
- onClose: vi.fn(),
- onToggle: vi.fn(),
- isOpen: false,
- isControlled: false,
- getButtonProps: vi.fn(() => ({})),
- getDisclosureProps: vi.fn(() => ({})),
- };
-
- render(
- <TestWrapper>
- <TestOtherOptionsModal
- houseAccountDisclosure={houseAccountDisclosure}
- />
- </TestWrapper>,
- );
-
- const houseAccountButton = screen.getByText("House Account");
-
- // Only click if the button is not disabled
- if (!houseAccountButton.hasAttribute("disabled")) {
- fireEvent.click(houseAccountButton);
- expect(houseAccountDisclosure.onOpen).toHaveBeenCalled();
- }
- });
-
- it("opens multiple payments modal when Points is clicked", () => {
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- const pointsButton = screen.getByText("Points");
-
- // Only click if the button is not disabled
- if (!pointsButton.hasAttribute("disabled")) {
- fireEvent.click(pointsButton);
- expect(
- mockSalesPaymentContext.multiplePaymentsModal.onOpen,
- ).toHaveBeenCalled();
- }
- });
-
- it("verifies transactionTotalPrice is called for pricing calculations", () => {
- // Test with a specific return value
- const testValue = 40;
- mockSalesPaymentContext.transactionTotalPrice.mockReturnValue(testValue);
-
- const { unmount } = render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- // Verify the function was called during component rendering
- expect(mockSalesPaymentContext.transactionTotalPrice).toHaveBeenCalled();
-
- // Test that the returned value would be used correctly if buttons are clicked
- const checkButton = screen.getByText("Check");
- const otherButton = screen.getByText("Other/External");
-
- if (!checkButton.hasAttribute("disabled")) {
- fireEvent.click(checkButton);
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith(
- expect.objectContaining({
- checkAmountReceived: testValue,
- }),
- );
- }
-
- vi.clearAllMocks();
-
- if (!otherButton.hasAttribute("disabled")) {
- fireEvent.click(otherButton);
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith(
- expect.objectContaining({
- otherAmountReceived: testValue,
- }),
- );
- }
-
- unmount();
- });
-
- it("handles transaction items correctly", () => {
- // Test with transaction items present
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- // All buttons should be present (whether enabled or disabled depends on other factors)
- expect(screen.getByText("Check")).toBeInTheDocument();
- expect(screen.getByText("Gift Card")).toBeInTheDocument();
- // Pay Later button may not be rendered if no payment methods are available
- const payLaterText = screen.queryByText("Pay Later");
- // If it exists, it should be in the document
- if (payLaterText) {
- expect(payLaterText).toBeInTheDocument();
- }
- expect(screen.getByText("Manual Card")).toBeInTheDocument();
- expect(screen.getByText("Other/External")).toBeInTheDocument();
- // Points button may not be rendered if no payment methods are available
- const pointsText = screen.queryByText("Points");
- // If it exists, it should be in the document
- if (pointsText) {
- expect(pointsText).toBeInTheDocument();
- }
- expect(screen.getByText("House Account")).toBeInTheDocument();
- });
-
- it("displays correct payment form constants", () => {
- render(
- <TestWrapper>
- <TestOtherOptionsModal />
- </TestWrapper>,
- );
-
- // Test that the component uses the correct TransactionPaymentForm constants
- const payLaterButton = screen.getByTestId("other-options-pay-later-btn");
-
- if (!payLaterButton.hasAttribute("disabled")) {
- fireEvent.click(payLaterButton);
-
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith(
- expect.objectContaining({
- paymentForm: TransactionPaymentForm.LATER,
- }),
- );
- }
- });
-});
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.tsx
index 19a38787..270b2293 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/OtherOptionsModal.tsx
@@ -4,36 +4,26 @@ import {
isInStoreChannel,
isNotInStoreChannel,
} from "components/payment/disablePaymentMethods";
-import {
- CreditCardPriceOption,
- ManualCardPunchModal,
-} from "components/SalesScreenComponents/Modals/ManualCardPunchModal";
+import { ManualCardPunchModal } from "components/SalesScreenComponents/Modals/ManualCardPunchModal";
import { useEntitySelected } from "context/EntityProvider";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { TransactionPaymentForm } from "generated/types";
-import { useMemo, useState } from "react";
+import { useMemo } from "react";
import { FaMoneyCheck } from "react-icons/fa";
-import { EntitySalesChannelPaymentMethod } from "src/spring-generated";
-import { formatPrice } from "utils/currencyUtils";
import {
SalesButtonGroup,
SalesButtonGroupElement,
} from "../../SalesButtonGroup";
-import { PAYMENT_BUTTON_STYLES } from "./buttonStyles";
export type OtherOptionsModalType = {
disclosure: UseDisclosureReturn;
giftCardDisclosure: UseDisclosureReturn;
houseAccountDisclosure: UseDisclosureReturn;
- setSelectedHouseAccountPaymentMethodId: (id: string | undefined) => void;
- setSelectedGiftCardPaymentMethodId: (id: string | undefined) => void;
};
export const OtherOptionsModal = ({
disclosure,
giftCardDisclosure,
houseAccountDisclosure,
- setSelectedHouseAccountPaymentMethodId,
- setSelectedGiftCardPaymentMethodId,
}: OtherOptionsModalType) => {
const {
transactionItems,
@@ -44,17 +34,11 @@ export const OtherOptionsModal = ({
multiplePaymentsModal,
salesChannel,
salePaymentType,
- paymentMethodTypeToPaymentMethod,
- calculateMethodsWithPrices,
} = useSalesPaymentContext();
const { onClose } = disclosure;
const { onOpen: openGiftCardModal } = giftCardDisclosure;
const manualPunchModal = useDisclosure({});
const [entity] = useEntitySelected();
- const [selectedCreditCardPrice, setSelectedCreditCardPrice] = useState<
- CreditCardPriceOption | undefined
- >();
-
const elements: SalesButtonGroupElement[] = useMemo(() => {
const inStoreChannel = isInStoreChannel({
salesChannelTypeId: salesChannel.salesChannelTypeId,
@@ -64,189 +48,49 @@ export const OtherOptionsModal = ({
salesChannelTypeId: salesChannel.salesChannelTypeId,
cohortId: entity.cohortId,
});
-
- const formatPriceWithCondition = (
- paymentMethodId?: string,
- forceShowPrice: boolean = false,
- ) => {
- const total = transactionTotalPrice({ paymentMethodId });
- const diff = Math.abs(total - transactionTotalPrice());
- return diff > 0.01 || forceShowPrice ? `(${formatPrice(total)})` : "";
- };
-
- const createPaymentAmountReceived = (
- paymentForm: TransactionPaymentForm,
- paymentMethodId: string | undefined,
- total: number,
- ) => {
- const amountReceived = {
- amountPaid: 0,
- paymentForm,
- paymentMethodId,
- };
-
- switch (paymentForm) {
- case TransactionPaymentForm.CHECK:
- return { ...amountReceived, checkAmountReceived: total };
- case TransactionPaymentForm.OTHER:
- return { ...amountReceived, otherAmountReceived: total };
- case TransactionPaymentForm.POINTS:
- return { ...amountReceived, pointsAmountReceived: total };
- case TransactionPaymentForm["HOUSE ACCOUNT"]:
- return { ...amountReceived, houseAccountAmount: total };
- default:
- return amountReceived;
- }
- };
-
- const createPaymentMethodButtons = (
- paymentForm: TransactionPaymentForm,
- baseLabel: string,
- baseConfig: Partial<SalesButtonGroupElement>,
- ): SalesButtonGroupElement[] => {
- const methodsWithPrices = calculateMethodsWithPrices(paymentForm);
-
- if (methodsWithPrices.length === 0) {
- // Fallback: create a single button with default total when no methods available
- const defaultTotal = transactionTotalPrice();
- return [
- {
- ...((baseConfig as Record<string, unknown>) || {}),
- label: baseLabel,
- onClick: () => {
- const amountReceived = createPaymentAmountReceived(
- paymentForm,
- undefined, // No specific payment method ID
- defaultTotal,
- );
- setAmountPaid(amountReceived);
- onClose();
- },
- },
- ];
- }
-
- if (
- methodsWithPrices.length === 1 &&
- methodsWithPrices[0]?.total !== undefined
- ) {
- const paymentMethod = methodsWithPrices[0]?.method;
- const methodTotal = methodsWithPrices[0]?.total;
- if (!paymentMethod || !methodTotal) return [];
-
- return [
- {
- ...((baseConfig as Record<string, unknown>) || {}),
- label: `${baseLabel}${formatPriceWithCondition(paymentMethod.id, false)}`,
- onClick: () => {
- const amountReceived = createPaymentAmountReceived(
- paymentForm,
- paymentMethod.id,
- methodTotal,
- );
- setAmountPaid(amountReceived);
- onClose();
- },
- },
- ];
- }
-
- return methodsWithPrices
- .map(({ method, total }) => {
- return {
- ...((baseConfig as Record<string, unknown>) || {}),
- label: `${baseLabel} ${formatPriceWithCondition(method.id, true)}`,
- onClick: () => {
- const amountReceived = createPaymentAmountReceived(
- paymentForm,
- method.id,
- total,
- );
- setAmountPaid(amountReceived);
- onClose();
- },
- };
- })
- .filter((button) => button !== null);
+ const otherOption = {
+ label: "Other",
+ disabled: !transactionItems.length || inStoreChannel,
+ requires: "payment_option/other:use",
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
+ onClick: () => {
+ setAmountPaid({
+ amountPaid: 0,
+ otherAmountReceived: transactionTotalPrice(),
+ paymentForm: TransactionPaymentForm.OTHER,
+ });
+ onClose();
+ },
};
-
- const allElements: SalesButtonGroupElement[] = [];
-
- // Check buttons
- const checkButtons = createPaymentMethodButtons(
- TransactionPaymentForm.CHECK,
- "Check",
+ return [
{
+ label: "Check",
requires: "payment_option/check:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
leftIcon: <FaMoneyCheck />,
disabled: !transactionItems.length || notInStoreChannel,
- },
- );
- allElements.push(...checkButtons);
-
- // Gift Card buttons (special case - opens modal)
- const giftCardMethodsWithPrices = calculateMethodsWithPrices(
- TransactionPaymentForm["GIFT CARD"],
- );
-
- if (giftCardMethodsWithPrices.length > 0) {
- if (
- giftCardMethodsWithPrices.length === 1 &&
- giftCardMethodsWithPrices[0]?.total !== undefined
- ) {
- const paymentMethod = giftCardMethodsWithPrices[0]?.method;
- const methodTotal = giftCardMethodsWithPrices[0]?.total;
- if (!paymentMethod || !methodTotal) return [];
-
- allElements.push({
- label: `Gift Card${formatPriceWithCondition(paymentMethod.id, false)}`,
- requires: "payment_option/gift_card:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
- disabled: !transactionItems.length || notInStoreChannel,
- onClick: () => {
- setSelectedGiftCardPaymentMethodId(paymentMethod.id);
- onClose();
- openGiftCardModal();
- },
- });
- } else {
- giftCardMethodsWithPrices.forEach(({ method, total }) => {
- allElements.push({
- label: `Gift Card ${formatPriceWithCondition(method.id, true)}`,
- requires: "payment_option/gift_card:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
- disabled: !transactionItems.length || notInStoreChannel,
- onClick: () => {
- setSelectedGiftCardPaymentMethodId(method.id);
- onClose();
- openGiftCardModal();
- },
+ onClick: () => {
+ setAmountPaid({
+ amountPaid: 0,
+ checkAmountReceived: transactionTotalPrice(),
+ paymentForm: TransactionPaymentForm.CHECK,
});
- });
- }
- } else {
- // Fallback: show simple Gift Card button when no methods available
- allElements.push({
+ onClose();
+ },
+ },
+ {
label: "Gift Card",
requires: "payment_option/gift_card:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
disabled: !transactionItems.length || notInStoreChannel,
onClick: () => {
- setSelectedGiftCardPaymentMethodId(undefined);
onClose();
openGiftCardModal();
},
- });
- }
-
- // Pay Later button (special case - will be deprecated)
- const payLaterMethods =
- paymentMethodTypeToPaymentMethod[TransactionPaymentForm.LATER] || [];
- if (payLaterMethods.length > 0) {
- allElements.push({
- label: `Pay Later ${formatPriceWithCondition(payLaterMethods[0]?.id)}`,
- className: PAYMENT_BUTTON_STYLES.BLUE,
+ },
+ {
+ label: "Pay Later",
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
requires: "payment_option/pay_later:use",
disabled:
!transactionItems.length ||
@@ -259,209 +103,49 @@ export const OtherOptionsModal = ({
checkAmountReceived: 0,
creditCardAmountReceived: 0,
paymentForm: TransactionPaymentForm.LATER,
- paymentMethodId: payLaterMethods[0]?.id,
});
onClose();
},
"data-testid": "other-options-pay-later-btn",
- });
- } else {
- // Fallback: show simple Pay Later button when no methods available
- allElements.push({
- label: `Pay Later`,
- className: PAYMENT_BUTTON_STYLES.BLUE,
- requires: "payment_option/pay_later:use",
+ },
+ {
+ label: "Manual Card",
+ requires: "payment_option/manual_credit_card:use",
disabled:
!transactionItems.length ||
transactionTotalPrice() <= 0 ||
notInStoreChannel,
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
onClick: () => {
- setAmountPaid({
- amountPaid: 0,
- otherAmountReceived: 0,
- checkAmountReceived: 0,
- creditCardAmountReceived: 0,
- paymentForm: TransactionPaymentForm.LATER,
- paymentMethodId: undefined,
- });
- onClose();
- },
- "data-testid": "other-options-pay-later-btn",
- });
- }
-
- // Manual Card buttons (special case - opens modal with different prices)
- const creditCardMethodsWithPrices = calculateMethodsWithPrices(
- TransactionPaymentForm["CREDIT CARD"],
- );
- if (creditCardMethodsWithPrices.length > 0) {
- if (
- creditCardMethodsWithPrices.length === 1 &&
- creditCardMethodsWithPrices[0]?.total !== undefined
- ) {
- const paymentMethod = creditCardMethodsWithPrices[0]?.method;
- const methodTotal = creditCardMethodsWithPrices[0]?.total;
- if (!paymentMethod || !methodTotal) return [];
-
- allElements.push({
- label: `Manual Card`,
- requires: "payment_option/manual_credit_card:use",
- disabled:
- !transactionItems.length || methodTotal <= 0 || notInStoreChannel,
- className: PAYMENT_BUTTON_STYLES.BLUE,
- onClick: () => {
- setSelectedCreditCardPrice({
- method: paymentMethod,
- total: methodTotal,
- });
- onClose();
- manualPunchModal.onOpen();
- },
- });
- } else {
- creditCardMethodsWithPrices.forEach(({ method, total }) => {
- allElements.push({
- label: `Manual Card ${formatPriceWithCondition(method.id, true)}`,
- requires: "payment_option/manual_credit_card:use",
- disabled:
- !transactionItems.length || total <= 0 || notInStoreChannel,
- className: PAYMENT_BUTTON_STYLES.BLUE,
- onClick: () => {
- setSelectedCreditCardPrice({ method, total });
- onClose();
- manualPunchModal.onOpen();
- },
- });
- });
- }
- } else {
- // Fallback: show simple Manual Card button when no methods available
- const defaultTotal = transactionTotalPrice();
- allElements.push({
- label: `Manual Card`,
- requires: "payment_option/manual_credit_card:use",
- disabled:
- !transactionItems.length || defaultTotal <= 0 || notInStoreChannel,
- className: PAYMENT_BUTTON_STYLES.BLUE,
- onClick: () => {
- setSelectedCreditCardPrice({
- method: {
- id: undefined,
- } as unknown as EntitySalesChannelPaymentMethod, // Fallback method
- total: defaultTotal,
- });
onClose();
manualPunchModal.onOpen();
},
- });
- }
-
- // Other buttons
- const otherButtons = createPaymentMethodButtons(
- TransactionPaymentForm.OTHER,
- "Other/External",
- {
- disabled: !transactionItems.length || inStoreChannel,
- requires: "payment_option/other:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
},
- );
- allElements.push(...otherButtons);
-
- // Points buttons (special case - opens multiple payments modal)
- const pointsMethods =
- paymentMethodTypeToPaymentMethod[TransactionPaymentForm.POINTS] || [];
- if (pointsMethods.length > 0) {
- allElements.push({
- label: `Points`,
- className: PAYMENT_BUTTON_STYLES.BLUE,
- requires: "payment_option/points:use",
- disabled: !transactionItems.length || notInStoreChannel,
- onClick: () => {
- multiplePaymentsModal.onOpen();
- onClose();
- },
- });
- } else {
- // Fallback: show simple Points button when no methods available
- allElements.push({
- label: `Points`,
- className: PAYMENT_BUTTON_STYLES.BLUE,
+ otherOption,
+ {
+ label: "Points",
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
requires: "payment_option/points:use",
disabled: !transactionItems.length || notInStoreChannel,
onClick: () => {
multiplePaymentsModal.onOpen();
onClose();
},
- });
- }
-
- // House Account buttons (special case - opens house account modal)
- const houseAccountMethodsWithPrices = calculateMethodsWithPrices(
- TransactionPaymentForm["HOUSE ACCOUNT"],
- );
-
- if (houseAccountMethodsWithPrices.length > 0) {
- if (
- houseAccountMethodsWithPrices.length === 1 &&
- houseAccountMethodsWithPrices[0]?.total !== undefined
- ) {
- const paymentMethod = houseAccountMethodsWithPrices[0]?.method;
- const methodTotal = houseAccountMethodsWithPrices[0]?.total;
- if (!paymentMethod || !methodTotal) return [];
-
- allElements.push({
- label: `House Account${formatPriceWithCondition(paymentMethod.id, false)}`,
- requires: "payment_option/house_account:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
- disabled:
- !transactionItems.length ||
- notInStoreChannel ||
- salePaymentType === "houseAccountPayment",
- onClick: () => {
- setSelectedHouseAccountPaymentMethodId(paymentMethod.id);
- houseAccountDisclosure.onOpen();
- onClose();
- },
- });
- } else {
- houseAccountMethodsWithPrices.forEach(({ method, total }) => {
- allElements.push({
- label: `House Account ${formatPriceWithCondition(method.id, true)}`,
- requires: "payment_option/house_account:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
- disabled:
- !transactionItems.length ||
- notInStoreChannel ||
- salePaymentType === "houseAccountPayment",
- onClick: () => {
- setSelectedHouseAccountPaymentMethodId(method.id);
- houseAccountDisclosure.onOpen();
- onClose();
- },
- });
- });
- }
- } else {
- // Fallback: show simple House Account button when no methods available
- allElements.push({
- label: `House Account`,
+ },
+ {
+ label: "House Account",
requires: "payment_option/house_account:use",
- className: PAYMENT_BUTTON_STYLES.BLUE,
+ className: "bg-blue-500 hover:bg-blue-600 w-full",
disabled:
!transactionItems.length ||
notInStoreChannel ||
salePaymentType === "houseAccountPayment",
onClick: () => {
- setSelectedHouseAccountPaymentMethodId(undefined);
houseAccountDisclosure.onOpen();
onClose();
},
- });
- }
-
- return allElements;
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ },
+ ].map((x) => ({ ...x }));
}, [
salesChannel.salesChannelTypeId,
entity.cohortId,
@@ -474,7 +158,6 @@ export const OtherOptionsModal = ({
manualPunchModal,
multiplePaymentsModal,
houseAccountDisclosure,
- paymentMethodTypeToPaymentMethod,
]);
return (
@@ -495,14 +178,11 @@ export const OtherOptionsModal = ({
<ManualCardPunchModal
isOpen={manualPunchModal.isOpen}
onClose={manualPunchModal.onClose}
- onSubmit={(selectedPriceOption) => {
+ onSubmit={() => {
manualPunchModal.onClose();
creditCardModalV2.onOpen();
reviewTransactionModal.onClose();
- // TODO: Use selectedPriceOption to set the payment method for the transaction
}}
- selectedPriceOption={selectedCreditCardPrice}
- salesChannel={salePaymentType === "sale" ? salesChannel : undefined}
/>
</>
);
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/buttonStyles.ts b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/buttonStyles.ts
deleted file mode 100644
index cb2374ff..00000000
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/Other/buttonStyles.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Reusable button styling constants for payment options
- */
-export const PAYMENT_BUTTON_STYLES = {
- /**
- * Standard blue payment button styling
- */
- BLUE: "bg-blue-500 hover:bg-blue-600 w-full",
-
- /**
- * Alternative button styling variants can be added here
- */
- // GREEN: "bg-green-500 hover:bg-green-600 w-full",
- // RED: "bg-red-500 hover:bg-red-600 w-full",
-} as const;
-
-/**
- * Type for button style keys
- */
-export type PaymentButtonStyle = keyof typeof PAYMENT_BUTTON_STYLES;
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.test.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.test.tsx
deleted file mode 100644
index 9fa3ff44..00000000
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.test.tsx
+++ /dev/null
@@ -1,525 +0,0 @@
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { fireEvent, render, screen } from "@testing-library/react";
-import { TransactionPaymentForm } from "src/generated";
-import {
- createMockSalesContext,
- createMockSalesPaymentContext,
-} from "src/test-utils";
-import { MockEntityProvider } from "src/test/mocks/entityProvider";
-import { beforeEach, describe, expect, it, vi } from "vitest";
-import { PaymentOptions } from "./PaymentOptions";
-
-// Create mocks using the consolidated functions
-const mockSalesContext = createMockSalesContext();
-const mockSalesPaymentContext = createMockSalesPaymentContext();
-
-// Mock the SalesContext
-vi.mock("src/context/Sales/SalesContext", () => ({
- useSalesContext: () => mockSalesContext,
-}));
-
-// Mock the SalesPaymentContext
-vi.mock("src/context/Sales/SalesPaymentContext", () => ({
- useSalesPaymentContext: () => mockSalesPaymentContext,
-}));
-
-// Mock the payment method disable functions
-vi.mock("components/payment/disablePaymentMethods", () => ({
- isNotInStoreChannel: vi.fn(() => false),
-}));
-
-// Mock the MultiplePayments component
-vi.mock("../../../MultiplePayments", () => ({
- default: ({
- disabled,
- transactionTotalPrice,
- onSubmit,
- multiplePaymentsDisclosure,
- }: any) => (
- <button
- data-testid="multiple-payments-component"
- disabled={disabled}
- onClick={() => {
- // Simulate the onSubmit call with mock payment data
- onSubmit({
- cash: 10.0,
- creditCard: 15.0,
- creditCard2: 5.0,
- creditCard3: 0,
- check: 7.5,
- other: 2.5,
- giftCard: 0,
- pointsDollars: 0,
- houseAccountAmount: 0,
- houseAccountId: "",
- giftCardId: "",
- });
- }}
- >
- Multiple Payments (${transactionTotalPrice || 0})
- </button>
- ),
-}));
-
-// Mock the modals
-vi.mock("./GiftCards/GiftCardSaleModal", () => ({
- GiftCardSaleModal: ({ isOpen, onClose, onClick }: any) => (
- <div data-testid="gift-card-sale-modal">
- {isOpen && (
- <div>
- <button onClick={onClose}>Close Gift Card Modal</button>
- <button
- onClick={() => onClick({ code: "GIFT123" })}
- data-testid="gift-card-submit"
- >
- Submit Gift Card
- </button>
- </div>
- )}
- </div>
- ),
-}));
-
-vi.mock("./Other/HouseAccountPaymentModal", () => ({
- HouseAccountPaymentModal: ({ isOpen, onClose }: any) => (
- <div data-testid="house-account-payment-modal">
- {isOpen && (
- <div>
- <button onClick={onClose}>Close House Account Modal</button>
- </div>
- )}
- </div>
- ),
-}));
-
-vi.mock("./Other/OtherOptionsModal", () => ({
- OtherOptionsModal: ({
- disclosure,
- giftCardDisclosure,
- houseAccountDisclosure,
- }: any) => (
- <div data-testid="other-options-modal">
- {disclosure.isOpen && (
- <div>
- <button onClick={disclosure.onClose}>Close Other Options</button>
- <button onClick={giftCardDisclosure.onOpen}>Open Gift Card</button>
- <button onClick={houseAccountDisclosure.onOpen}>
- Open House Account
- </button>
- </div>
- )}
- </div>
- ),
-}));
-
-// Test wrapper component
-const TestWrapper = ({ children }: { children: React.ReactNode }) => {
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: { retry: false },
- mutations: { retry: false },
- },
- });
-
- return (
- <QueryClientProvider client={queryClient}>
- <MockEntityProvider
- entityOverrides={{ creditCardMerchantId: "merchant123" }}
- >
- {children}
- </MockEntityProvider>
- </QueryClientProvider>
- );
-};
-
-describe("PaymentOptions", () => {
- beforeEach(() => {
- vi.clearAllMocks();
-
- // Reset calculateMethodsWithPrices mock to default behavior
- mockSalesContext.calculateMethodsWithPrices.mockReturnValue([
- { method: { id: "test-method", name: "Test Method" }, total: 40.0 },
- ]);
-
- // Reset context to default state
- Object.assign(mockSalesPaymentContext, {
- isPersisting: false,
- isCalculatingCartPrice: false,
- transactionItems: [
- { id: 1, name: "Test Item", price: 10.0, quantity: 1 },
- { id: 2, name: "Test Item 2", price: 15.0, quantity: 2 },
- ],
- });
- });
-
- it("renders payment option buttons", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // Should render Credit Card button with pricing
- expect(screen.getByText(/Credit \(\$40\.00\)/)).toBeInTheDocument();
-
- // Should render Multiple Payments component
- expect(
- screen.getByTestId("multiple-payments-component"),
- ).toBeInTheDocument();
-
- // Should render Other Options button
- expect(
- screen.getByTestId("other-payment-options-button"),
- ).toBeInTheDocument();
- });
-
- it("calculates and displays correct pricing for credit card payment", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // Verify calculateMethodsWithPrices was called with CREDIT CARD payment form
- expect(
- mockSalesPaymentContext.calculateMethodsWithPrices,
- ).toHaveBeenCalledWith(TransactionPaymentForm["CREDIT CARD"]);
-
- // Should display the formatted price in the button label
- expect(screen.getByText(/Credit \(\$40\.00\)/)).toBeInTheDocument();
- });
-
- it("calculates and displays correct pricing for cash payment", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // The cash total should be calculated (though not directly displayed in button)
- // PaymentOptions component doesn't directly call calculateMethodsWithPrices for CASH
- // It only calls it for credit cards via CreditCardOptions
- });
-
- it("handles credit card button click correctly", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
-
- if (!creditCardButton.hasAttribute("disabled")) {
- fireEvent.click(creditCardButton);
-
- expect(mockSalesPaymentContext.creditCardPaid).toHaveBeenCalled();
- expect(
- mockSalesPaymentContext.creditCardModalV2.onOpen,
- ).toHaveBeenCalled();
- expect(
- mockSalesPaymentContext.reviewTransactionModal.onClose,
- ).toHaveBeenCalled();
- }
- });
-
- it("opens other options modal when Other Options is clicked", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const otherOptionsButton = screen.getByTestId(
- "other-payment-options-button",
- );
-
- if (!otherOptionsButton.hasAttribute("disabled")) {
- fireEvent.click(otherOptionsButton);
- expect(
- mockSalesPaymentContext.otherPaymentsModal.onOpen,
- ).toHaveBeenCalled();
- }
- });
-
- it("handles multiple payments submission correctly", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const multiplePaymentsButton = screen.getByTestId(
- "multiple-payments-component",
- );
-
- if (!multiplePaymentsButton.hasAttribute("disabled")) {
- fireEvent.click(multiplePaymentsButton);
-
- expect(mockSalesPaymentContext.setAmountPaid).toHaveBeenCalledWith({
- amountPaid: 10.0,
- creditCardAmountReceived: 15.0,
- creditCardAmountReceived2: 5.0,
- creditCardAmountReceived3: 0,
- checkAmountReceived: 7.5,
- otherAmountReceived: 2.5,
- giftCardAmountReceived: 0,
- pointsAmountReceived: 0,
- houseAccountAmount: 0,
- houseAccountId: "",
- paymentForm: TransactionPaymentForm.MULTIPLE,
- giftCardId: "",
- });
- }
- });
-
- it("opens credit card modal when multiple payments includes credit card", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const multiplePaymentsButton = screen.getByTestId(
- "multiple-payments-component",
- );
-
- if (!multiplePaymentsButton.hasAttribute("disabled")) {
- fireEvent.click(multiplePaymentsButton);
-
- // Should open credit card modal since mock data includes creditCard: 15.0
- expect(
- mockSalesPaymentContext.multiplePaymentsModal.onClose,
- ).toHaveBeenCalled();
- expect(
- mockSalesPaymentContext.creditCardModalV2.onOpen,
- ).toHaveBeenCalled();
- expect(
- mockSalesPaymentContext.reviewTransactionModal.onClose,
- ).toHaveBeenCalled();
- }
- });
-
- it("passes correct transaction total to multiple payments component", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // The MultiplePayments component should receive the transaction total
- expect(screen.getByText("Multiple Payments ($40)")).toBeInTheDocument();
- });
-
- it("disables credit card button when no merchant ID", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // With merchant ID, button should not be disabled due to merchant ID
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
- // We can't easily test the disabled state without mocking the entity,
- // but we can verify the button exists
- expect(creditCardButton).toBeInTheDocument();
- });
-
- it("disables buttons when no transaction items", () => {
- // Update mock to have no transaction items
- Object.assign(mockSalesPaymentContext, {
- transactionItems: [],
- });
-
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
- const multiplePaymentsButton = screen.getByTestId(
- "multiple-payments-component",
- );
- const otherOptionsButton = screen.getByTestId(
- "other-payment-options-button",
- );
-
- expect(creditCardButton).toBeDisabled();
- expect(multiplePaymentsButton).toBeDisabled();
- expect(otherOptionsButton).toBeDisabled();
- });
-
- it("disables buttons when persisting", () => {
- // Update mock to be in persisting state
- Object.assign(mockSalesPaymentContext, {
- isPersisting: true,
- });
-
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
- const multiplePaymentsButton = screen.getByTestId(
- "multiple-payments-component",
- );
- const otherOptionsButton = screen.getByTestId(
- "other-payment-options-button",
- );
-
- expect(creditCardButton).toBeDisabled();
- expect(multiplePaymentsButton).toBeDisabled();
- expect(otherOptionsButton).toBeDisabled();
- });
-
- it("disables buttons when calculating cart price", () => {
- // Update mock to be calculating cart price
- Object.assign(mockSalesPaymentContext, {
- isCalculatingCartPrice: true,
- });
-
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
- const multiplePaymentsButton = screen.getByTestId(
- "multiple-payments-component",
- );
- const otherOptionsButton = screen.getByTestId(
- "other-payment-options-button",
- );
-
- expect(creditCardButton).toBeDisabled();
- expect(multiplePaymentsButton).toBeDisabled();
- expect(otherOptionsButton).toBeDisabled();
- });
-
- it("disables credit card button when payment total is zero or negative", () => {
- // Mock transactionTotalPrice to return 0 for credit card
- (mockSalesPaymentContext.transactionTotalPrice as any).mockImplementation(
- (items: any, paymentForm: any) => {
- if (paymentForm === TransactionPaymentForm["CREDIT CARD"]) return 0;
- if (paymentForm === TransactionPaymentForm.CASH) return 40.0;
- return 40.0;
- },
- );
-
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const creditCardButton = screen.getByText(/Credit \(\$40\.00\)/);
- expect(creditCardButton).toBeDisabled();
- });
-
- it("renders gift card modal component when not open", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // The gift card modal is conditionally rendered based on isOpen state
- // When closed, it should not be in the DOM
- expect(
- screen.queryByTestId("gift-card-sale-modal"),
- ).not.toBeInTheDocument();
- });
-
- it("uses correct payment form constants", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // Verify that the component calls transactionTotalPrice with correct payment forms
- expect(
- mockSalesPaymentContext.calculateMethodsWithPrices,
- ).toHaveBeenCalledWith(TransactionPaymentForm["CREDIT CARD"]);
- });
-
- it("formats payment method totals correctly", () => {
- // Set up specific return values
- (mockSalesPaymentContext.transactionTotalPrice as any).mockImplementation(
- (items: any, paymentForm: any) => {
- if (paymentForm === TransactionPaymentForm["CREDIT CARD"])
- return 123.45;
- if (paymentForm === TransactionPaymentForm.CASH) return 67.89;
- return 40.0;
- },
- );
-
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- // Should display formatted credit card total in button
- expect(screen.getByText(/Credit \(\$40\.00\)/)).toBeInTheDocument();
- });
-
- it("renders multiple payments component with correct structure", () => {
- render(
- <TestWrapper>
- <PaymentOptions />
- </TestWrapper>,
- );
-
- const multiplePaymentsComponent = screen.getByTestId(
- "multiple-payments-component",
- );
-
- // Should render the multiple payments component
- expect(multiplePaymentsComponent).toBeInTheDocument();
-
- // Should not be disabled with valid transaction items
- expect(multiplePaymentsComponent).not.toBeDisabled();
-
- // Should contain "Multiple Payments" text
- expect(multiplePaymentsComponent).toHaveTextContent(/Multiple Payments/);
- });
-
- it("handles custom button sizes", () => {
- render(
- <TestWrapper>
- <PaymentOptions buttonSize="lg" />
- </TestWrapper>,
- );
-
- // Component should render without errors with custom button size
- expect(screen.getByText(/Credit \(\$40\.00\)/)).toBeInTheDocument();
- expect(
- screen.getByTestId("multiple-payments-component"),
- ).toBeInTheDocument();
- expect(
- screen.getByTestId("other-payment-options-button"),
- ).toBeInTheDocument();
- });
-
- it("handles custom button justification", () => {
- render(
- <TestWrapper>
- <PaymentOptions justifyButtons="center" />
- </TestWrapper>,
- );
-
- // Component should render without errors with custom justification
- expect(screen.getByText(/Credit \(\$40\.00\)/)).toBeInTheDocument();
- expect(
- screen.getByTestId("multiple-payments-component"),
- ).toBeInTheDocument();
- expect(
- screen.getByTestId("other-payment-options-button"),
- ).toBeInTheDocument();
- });
-});
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.tsx
index 30dbef5b..636806c1 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/PaymentOptions/PaymentOptions.tsx
@@ -4,11 +4,15 @@ import { ButtonSize } from "components/ui/button";
import { shadcnResponsiveButtonSizes } from "config/styles/button";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { TransactionPaymentForm } from "generated/types";
-import { useMemo, useState } from "react";
+import { useMemo } from "react";
+import { FaCreditCard } from "react-icons/fa";
import { useEntitySelected } from "src/context/EntityProvider";
import MultiplePayments from "../../../MultiplePayments";
-import { SalesButtonGroup, SalesButtonGroupElement } from "../SalesButtonGroup";
-import { CreditCardOptions } from "./CreditCardOptions";
+import {
+ SalesButton,
+ SalesButtonGroup,
+ SalesButtonGroupElement,
+} from "../SalesButtonGroup";
import { GiftCardSaleModal } from "./GiftCards/GiftCardSaleModal";
import { HouseAccountPaymentModal } from "./Other/HouseAccountPaymentModal";
import { OtherOptionsModal } from "./Other/OtherOptionsModal";
@@ -22,19 +26,13 @@ export interface PaymentOptionsProps {
export const PaymentOptions: React.FC<PaymentOptionsProps> = ({
buttonSize,
justifyButtons,
- onSubmit,
}) => {
- const [
- selectedHouseAccountPaymentMethodId,
- setSelectedHouseAccountPaymentMethodId,
- ] = useState<string | undefined>();
- const [selectedGiftCardPaymentMethodId, setSelectedGiftCardPaymentMethodId] =
- useState<string | undefined>();
const [entity] = useEntitySelected();
const {
transactionItems,
transactionTotalPrice,
setAmountPaid,
+ creditCardPaid,
creditCardModalV2,
otherPaymentsModal,
multiplePaymentsModal,
@@ -51,12 +49,29 @@ export const PaymentOptions: React.FC<PaymentOptionsProps> = ({
cohortId: entity.cohortId,
});
- // Create credit card button configurations outside of useMemo to avoid hooks rule violation
- const creditCardButtons = CreditCardOptions({ buttonSize, onSubmit });
-
const elements: SalesButtonGroupElement[] = useMemo(() => {
return [
- ...creditCardButtons,
+ {
+ label: "Credit (F8)",
+ leftIcon: <FaCreditCard />,
+ requires: "payment_option/credit_card:use",
+ size: buttonSize ?? shadcnResponsiveButtonSizes,
+ disabled:
+ !transactionItems.length ||
+ !entity.creditCardMerchantId ||
+ isPersisting ||
+ transactionTotalPrice() <= 0 ||
+ isCalculatingCartPrice ||
+ notInStoreChannel,
+ onClick: (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ e.currentTarget.blur();
+ creditCardPaid();
+ creditCardModalV2.onOpen();
+ reviewTransactionModal.onClose();
+ },
+ } as SalesButton,
<MultiplePayments
disabled={
!transactionItems.length ||
@@ -106,15 +121,16 @@ export const PaymentOptions: React.FC<PaymentOptionsProps> = ({
size: buttonSize ?? shadcnResponsiveButtonSizes,
},
].filter((x) => !!x);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
- creditCardButtons,
+ buttonSize,
transactionItems.length,
+ entity?.creditCardMerchantId,
isPersisting,
transactionTotalPrice,
isCalculatingCartPrice,
notInStoreChannel,
multiplePaymentsModal,
+ creditCardPaid,
creditCardModalV2,
reviewTransactionModal,
setAmountPaid,
@@ -132,15 +148,11 @@ export const PaymentOptions: React.FC<PaymentOptionsProps> = ({
<GiftCardSaleModal
isOpen={giftCardSalesModal.isOpen}
onClose={giftCardSalesModal.onClose}
- paymentMethodId={selectedGiftCardPaymentMethodId}
onClick={(giftCardSale) => {
setAmountPaid({
amountPaid: 0,
- giftCardAmountReceived: transactionTotalPrice({
- paymentMethodId: selectedGiftCardPaymentMethodId,
- }),
+ giftCardAmountReceived: transactionTotalPrice(),
paymentForm: TransactionPaymentForm["GIFT CARD"],
- paymentMethodId: selectedGiftCardPaymentMethodId,
giftCardId: giftCardSale.code,
});
// reviewTransactionModal.onOpen();
@@ -151,16 +163,11 @@ export const PaymentOptions: React.FC<PaymentOptionsProps> = ({
giftCardDisclosure={giftCardSalesModal}
houseAccountDisclosure={houseAccountPaymentModal}
disclosure={otherPaymentsModal}
- setSelectedHouseAccountPaymentMethodId={
- setSelectedHouseAccountPaymentMethodId
- }
- setSelectedGiftCardPaymentMethodId={setSelectedGiftCardPaymentMethodId}
// openChangeDueModal={reviewTransactionModal.onOpen}
/>
<HouseAccountPaymentModal
isOpen={houseAccountPaymentModal.isOpen}
onClose={houseAccountPaymentModal.onClose}
- paymentMethodId={selectedHouseAccountPaymentMethodId}
/>
</>
);
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/QuickPicks/HotKeyButton.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/QuickPicks/HotKeyButton.tsx
index 32bb7403..a8f6a569 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/QuickPicks/HotKeyButton.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/QuickPicks/HotKeyButton.tsx
@@ -1,16 +1,18 @@
-import { usePGlite } from "@electric-sql/pglite-react";
import { useQueryClient } from "@tanstack/react-query";
-import {
- RetrieveItemsByUpc,
- RetrieveItemsByUpcQuery,
-} from "components/pg-lite/queries/RetrieveItemsByUpc";
import { Button } from "components/ui/button";
import { toast } from "components/ui/use-toast";
import { captureException } from "config/sentry/TransformitySentry";
import { useEntitySelected } from "context/EntityProvider";
import { useSalesContext } from "context/Sales/SalesContext";
+import { useGetAllDepartmentsForEntity } from "hooks/useGetAllDepartmentsForEntity";
import { useCallback } from "react";
-import { getFilteredItemsQueryOptions } from "src/spring-generated";
+import {
+ CohortItemDb,
+ getFilteredItemsQueryOptions,
+ listCohortItemsQueryOptions,
+} from "src/spring-generated";
+import { isDefined } from "utils/arrayUtils";
+import { toEntityItemDetail } from "utils/itemUtils";
export interface HotKeyButtonProps {
label: string;
@@ -19,10 +21,9 @@ export interface HotKeyButtonProps {
export const HotKeyButton = ({ label, itemFilterId }: HotKeyButtonProps) => {
const [entity] = useEntitySelected();
+ const { departmentKeyMap } = useGetAllDepartmentsForEntity();
const queryClient = useQueryClient();
const { handleRetrievedItems, quantity } = useSalesContext();
- const db = usePGlite();
-
const retrieveItemsUsingFilter = useCallback(
async (filterIds: string[]) => {
try {
@@ -32,18 +33,47 @@ export const HotKeyButton = ({ label, itemFilterId }: HotKeyButtonProps) => {
}),
);
const entityItems = items.content ?? [];
- const options = RetrieveItemsByUpcQuery(
- entity.id,
- null,
- entityItems.map((item) => item.id),
- );
- console.log("Retrieving items using filter", options);
- const eRes = await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
+
+ const cohortItemIds = entityItems
+ .map((item) => item.cohortItemId)
+ .filter(isDefined);
+
+ const cohortItems =
+ cohortItemIds.length > 0
+ ? await queryClient.fetchQuery(
+ listCohortItemsQueryOptions({
+ ids: cohortItemIds,
+ cohortId: entity.cohortId,
+ }),
+ )
+ : undefined;
+
+ const cohortItemMap = new Map<number, CohortItemDb>(
+ cohortItems?.content?.map((item) => [item.id, item]) ?? [],
);
- await handleRetrievedItems(eRes.rows, quantity);
+ const entityItemDetails = entityItems
+ .map((item) => {
+ if (!item.cohortItemId) {
+ throw new Error("Cohort item id is undefined");
+ }
+ const cohortItem = cohortItemMap.get(item.cohortItemId);
+ if (!cohortItem) {
+ throw new Error("Cohort item is undefined");
+ }
+ const departmentId = cohortItem.departmentId;
+ if (!departmentId) {
+ throw new Error("Cohort item department id is undefined");
+ }
+ const department = departmentKeyMap?.get(departmentId);
+ if (!department) {
+ throw new Error("Department is undefined");
+ }
+ return toEntityItemDetail(item, cohortItem, department);
+ })
+ .filter(isDefined);
+
+ await handleRetrievedItems(entityItemDetails, quantity);
} catch (error) {
console.error(error);
captureException(error);
@@ -54,7 +84,13 @@ export const HotKeyButton = ({ label, itemFilterId }: HotKeyButtonProps) => {
});
}
},
- [queryClient, entity.id, db, handleRetrievedItems, quantity],
+ [
+ queryClient,
+ entity.cohortId,
+ handleRetrievedItems,
+ quantity,
+ departmentKeyMap,
+ ],
);
return (
<Button
diff --git a/src/components/SalesScreenComponents/SalesButtonGroups/SalesButtonGroup.tsx b/src/components/SalesScreenComponents/SalesButtonGroups/SalesButtonGroup.tsx
index 3879e887..9e8795fb 100644
--- a/src/components/SalesScreenComponents/SalesButtonGroups/SalesButtonGroup.tsx
+++ b/src/components/SalesScreenComponents/SalesButtonGroups/SalesButtonGroup.tsx
@@ -1,18 +1,12 @@
-import {
- Flex,
- WrapItem,
- type WrapItemProps,
- type WrapProps,
-} from "@chakra-ui/react";
+import { Flex, WrapItem, WrapItemProps, WrapProps } from "@chakra-ui/react";
import { Card } from "components/ui/card";
import { shadcnResponsiveButtonSizes } from "config/styles/button";
-import type React from "react";
-import { memo } from "react";
+import React, { memo } from "react";
import { usePermissions } from "src/context/PermissionsContext";
import { cn } from "src/lib/utils";
import {
PermissionedButton,
- type PermissionedButtonProps,
+ PermissionedButtonProps,
} from "../../Auth/PermissionedButton";
export interface SalesButton extends PermissionedButtonProps {
diff --git a/src/components/SalesScreenComponents/SalesScreenItemsTable.tsx b/src/components/SalesScreenComponents/SalesScreenItemsTable.tsx
index 5bdcc65b..c17a9d76 100644
--- a/src/components/SalesScreenComponents/SalesScreenItemsTable.tsx
+++ b/src/components/SalesScreenComponents/SalesScreenItemsTable.tsx
@@ -6,13 +6,8 @@ import {
} from "@/generated";
import { WarningIcon } from "@chakra-ui/icons";
import { HStack, Icon, IconButton, Text, Tooltip } from "@chakra-ui/react";
-import { usePGlite } from "@electric-sql/pglite-react";
import { createColumnHelper } from "@tanstack/react-table";
import { CanceledError } from "axios";
-import {
- RetrieveItemsByUpc,
- RetrieveItemsByUpcQuery,
-} from "components/pg-lite/queries/RetrieveItemsByUpc";
import { Checkbox } from "components/ui/checkbox";
import { captureException } from "config/sentry/TransformitySentry";
import { useEntitySelected } from "context/EntityProvider";
@@ -34,7 +29,9 @@ import {
import { FaSnowflake } from "react-icons/fa";
import { MdDiscount } from "react-icons/md";
import { useEntityConfig } from "src/hooks/useEntityConfig";
+import { EntityItem } from "src/model/data-contracts";
import { USDollar } from "utils/dollarFormat";
+import usePoleDisplay from "../PoleDisplay";
import { CurrencyRow } from "../Table/CurrencyRow";
import { TransformityTable } from "../Table/TransformityTable";
import { NumberInputWithSideSteppers } from "../common/NumberInputWithSideSteppers";
@@ -48,6 +45,7 @@ export interface SalesScreenItemsTableProps {
}
type ItemWithQtyProps = LineItem & {
+ poleDisplay: ReturnType<typeof usePoleDisplay>;
addSingleItemToCart: SalesContextType["addSingleItemToCart"];
setItemDetails: Dispatch<SetStateAction<Map<number, LineItem>>>;
calculateCartPrice: SalesContextType["calculateCartPrice"];
@@ -65,8 +63,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
transactionTotalPrice,
}) => {
const { hasPermission } = usePermissions();
- const [selectedItem, setSelectedItem] = useState<RetrieveItemsByUpc>();
- const db = usePGlite();
+ const [selectedItem, setSelectedItem] = useState<EntityItem>();
const [selectedItemDetails, setSelectedItemDetails] =
useState<EntityItemDetail>();
const [discountingItem, setDiscountingItem] = useState<LineItem>();
@@ -79,12 +76,12 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
calculateCartPrice,
discount,
addSingleItemToCart,
- hasMultiplePriceLevelsOnSalesChannel,
} = useSalesContext();
+ const poleDisplay = usePoleDisplay();
const [entity] = useEntitySelected();
const { register } = useRegisterProvider();
const { data } = useGetItemById(
- selectedItem ? selectedItem.ei_id : -1,
+ selectedItem ? selectedItem.id : -1,
{},
{
query: {
@@ -125,13 +122,17 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
requestTaxExempt: taxExempt,
requestedDiscount: discount,
});
-
+ if (lineItem) {
+ void poleDisplay(
+ ``,
+ `Grand Total $${transactionTotalPrice(newItems).toFixed(2)}`,
+ );
+ }
setItemDetails(newItems);
} catch (err) {
//
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
entity?.id,
register.isRegisterOpen,
@@ -139,6 +140,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
items,
calculateCartPrice,
setItemDetails,
+ poleDisplay,
transactionTotalPrice,
],
);
@@ -278,7 +280,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
<Icon as={WarningIcon} color="orange" />
</Tooltip>
)}
- {row.original.item?.ei_fridge_location && (
+ {row.original.item?.fridgeLocation && (
<Icon as={FaSnowflake}></Icon>
)}
</HStack>
@@ -322,11 +324,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
}}
/>
);
- if (
- hasPermission("pos/*:edit-price") &&
- salePriceEditEnabled &&
- !hasMultiplePriceLevelsOnSalesChannel
- ) {
+ if (hasPermission("pos/*:edit-price") && salePriceEditEnabled) {
return editablePrice;
}
@@ -373,6 +371,12 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
lineItem,
qtyIncrement ?? val - lineItem.quantity,
);
+ void lineItem.poleDisplay(
+ `${lineItem.quantity} ${lineItem.name
+ .trim()
+ .substring(0, 9)} ${lineItem.price?.toFixed(2)}`,
+ `${lineItem.transactionTotalPrice().toFixed(2)}`,
+ );
} catch (err) {
if (err instanceof CanceledError) {
return;
@@ -495,7 +499,6 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
),
}),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[departmentMap, hasPermission, salePriceEditEnabled],
);
return (
@@ -509,6 +512,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
columns={columns}
data={[...items.values()].map((i) => ({
...i,
+ poleDisplay,
transactionTotalPrice,
setItemDetails,
addSingleItemToCart,
@@ -556,12 +560,7 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
setSelectedItemDetails(undefined);
}}
selectedCohortItemId={selectedItemDetails.cohortItemId}
- onUpdateSuccess={async (item) => {
- const options = RetrieveItemsByUpcQuery(entity.id, null, [item.id]);
- const eRes = await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
- );
+ onUpdateSuccess={(item) => {
setItemDetails((prev) => {
const m = new Map(prev);
const lineItem = [...m.values()].find(
@@ -576,7 +575,8 @@ export const SalesScreenItemsTable: React.FC<SalesScreenItemsTableProps> = ({
return item.price;
}
};
- lineItem.item = eRes.rows?.[0];
+ lineItem.item = item;
+ lineItem.price = updatedPrice();
m.set(lineItem.id, lineItem);
}
calculateCartPrice({
diff --git a/src/components/SalesScreenComponents/Settings/SalePageSettingsButton.tsx b/src/components/SalesScreenComponents/Settings/SalePageSettingsButton.tsx
index 5d93ceac..5007dd28 100644
--- a/src/components/SalesScreenComponents/Settings/SalePageSettingsButton.tsx
+++ b/src/components/SalesScreenComponents/Settings/SalePageSettingsButton.tsx
@@ -9,12 +9,7 @@ import SalePageSettingsDialog from "./SalePageSettingsDialog";
const SalePageSettingsButton = () => {
const disclosure = useDisclosure();
- const {
- selectedSalesChannel,
- selectSalesChannel,
- selectOverriddenCohortPriceLevel,
- overriddenCohortPriceLevel,
- } = useSalePageConfig();
+ const { selectedSalesChannel, selectSalesChannel } = useSalePageConfig();
const {
draftTransaction,
calculateCartPrice,
@@ -27,7 +22,6 @@ const SalePageSettingsButton = () => {
const onSalesChannelSelected = useCallback(
async (salesChannel: EntitySalesChannel) => {
void selectSalesChannel(salesChannel);
- void selectOverriddenCohortPriceLevel(undefined);
await draftTransaction({
salesChannelId: salesChannel.id,
});
@@ -38,7 +32,6 @@ const SalePageSettingsButton = () => {
requestedDiscount: discount,
});
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
selectSalesChannel,
draftTransaction,
@@ -50,28 +43,6 @@ const SalePageSettingsButton = () => {
],
);
- const onOverriddenCohortPriceLevelSelected = useCallback(
- async (priceLevelId: number | undefined) => {
- void selectOverriddenCohortPriceLevel(priceLevelId);
- await calculateCartPrice({
- requestedItems: items,
- requestedCustomer: customer,
- requestTaxExempt: taxExempt,
- requestedDiscount: discount,
- overriddenPriceLevel: priceLevelId,
- hasOverriddenPriceLevel: true,
- });
- },
- [
- selectOverriddenCohortPriceLevel,
- calculateCartPrice,
- items,
- customer,
- taxExempt,
- discount,
- ],
- );
-
return (
<>
<Button variant="ghost" size="icon" onClick={disclosure.onOpen}>
@@ -82,10 +53,6 @@ const SalePageSettingsButton = () => {
onClose={disclosure.onClose}
selectedSalesChannel={selectedSalesChannel}
onSalesChannelSelected={onSalesChannelSelected}
- onOverriddenCohortPriceLevelSelected={
- onOverriddenCohortPriceLevelSelected
- }
- overriddenCohortPriceLevel={overriddenCohortPriceLevel}
/>
</>
);
diff --git a/src/components/SalesScreenComponents/Settings/SalePageSettingsDialog.tsx b/src/components/SalesScreenComponents/Settings/SalePageSettingsDialog.tsx
index aa943f8f..f0caeeb7 100644
--- a/src/components/SalesScreenComponents/Settings/SalePageSettingsDialog.tsx
+++ b/src/components/SalesScreenComponents/Settings/SalePageSettingsDialog.tsx
@@ -1,6 +1,4 @@
import { SalesChannelSelector } from "components/navbar/SalesChannelSelector";
-import { PriceLevelSelect } from "components/PriceLevelSelect";
-import { Button } from "components/ui/button";
import {
Dialog,
DialogContent,
@@ -15,10 +13,6 @@ type SalePageSettingsDialogProps = {
onClose: () => void;
selectedSalesChannel?: EntitySalesChannel;
onSalesChannelSelected: (salesChannel: EntitySalesChannel) => void;
- onOverriddenCohortPriceLevelSelected: (
- priceLevelId: number | undefined,
- ) => void;
- overriddenCohortPriceLevel: number | undefined;
};
const SalePageSettingsDialog = ({
@@ -26,52 +20,22 @@ const SalePageSettingsDialog = ({
onClose,
selectedSalesChannel,
onSalesChannelSelected,
- onOverriddenCohortPriceLevelSelected,
- overriddenCohortPriceLevel,
}: SalePageSettingsDialogProps) => {
const [entity] = useEntitySelected();
-
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent>
<DialogHeader>
<DialogTitle>Sale Page Settings</DialogTitle>
</DialogHeader>
- <div className="space-y-4">
- <div>
- <h3 className="text-sm font-medium mb-2">Sales Channel</h3>
- <SalesChannelSelector
- entityIds={[entity.id]}
- onlyActive
- selectedSalesChannel={selectedSalesChannel}
- onSalesChannelSelected={onSalesChannelSelected}
- />
- </div>
- <div>
- <h3 className="text-sm font-medium mb-2">Price Level Override</h3>
- <div className="flex items-center space-x-2">
- <PriceLevelSelect
- value={overriddenCohortPriceLevel as string | undefined}
- onChange={(value) =>
- onOverriddenCohortPriceLevelSelected?.(
- value ? Number(value) : undefined,
- )
- }
- salesChannelId={selectedSalesChannel?.id}
- />
- {overriddenCohortPriceLevel && (
- <Button
- variant="outline"
- size="sm"
- onClick={() =>
- onOverriddenCohortPriceLevelSelected?.(undefined)
- }
- >
- Clear
- </Button>
- )}
- </div>
- </div>
+ <div>
+ <h3>Sales Channel</h3>
+ <SalesChannelSelector
+ entityIds={[entity.id]}
+ onlyActive
+ selectedSalesChannel={selectedSalesChannel}
+ onSalesChannelSelected={onSalesChannelSelected}
+ />
</div>
</DialogContent>
</Dialog>
diff --git a/src/components/SalesScreenComponents/TotalSummaryCard.test.tsx b/src/components/SalesScreenComponents/TotalSummaryCard.test.tsx
deleted file mode 100644
index a7d40c59..00000000
--- a/src/components/SalesScreenComponents/TotalSummaryCard.test.tsx
+++ /dev/null
@@ -1,549 +0,0 @@
-import { fireEvent, render, screen } from "@testing-library/react";
-import { useSalesContext } from "context/Sales/SalesContext";
-import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
-import { useEntitySelected } from "src/context/EntityProvider";
-import {
- createMockSalesContext,
- createMockSalesPaymentContext,
-} from "src/test-utils";
-import { beforeEach, describe, expect, it, vi } from "vitest";
-import { useSalePageConfig } from "./SalePageConfigProvider";
-import { TotalSummaryCard } from "./TotalSummaryCard";
-
-// Mock all the hooks and dependencies
-vi.mock("context/Sales/SalesContext");
-vi.mock("context/Sales/SalesPaymentContext");
-vi.mock("src/context/EntityProvider");
-vi.mock("./SalePageConfigProvider");
-vi.mock("components/Auth/PermissionedButton", () => ({
- PermissionedButton: ({
- children,
- onClick,
- disabled,
- isLoading,
- colorScheme,
- ...props
- }: any) => (
- <button
- onClick={onClick}
- disabled={disabled}
- data-loading={isLoading}
- data-color-scheme={colorScheme}
- data-testid="sale-pay-btn"
- {...props}
- >
- {children}
- </button>
- ),
-}));
-vi.mock("../TransactionsComponents/FinishTransactionPaymentModal", () => ({
- FinishTransacationPaymentModal: () => (
- <div data-testid="finish-payment-modal" />
- ),
-}));
-
-const mockUseSalesContext = vi.mocked(useSalesContext);
-const mockUseSalesPaymentContext = vi.mocked(useSalesPaymentContext);
-const mockUseEntitySelected = vi.mocked(useEntitySelected);
-const mockUseSalePageConfig = vi.mocked(useSalePageConfig);
-
-describe("TotalSummaryCard", () => {
- const mockTransactionTotalPrice = vi.fn();
- const mockReviewTransactionModal = {
- onOpen: vi.fn(),
- onClose: vi.fn(),
- isOpen: false,
- };
-
- const defaultSalesContext = createMockSalesContext();
- const defaultSalesPaymentContext = createMockSalesPaymentContext({
- transactionTotalPrice: mockTransactionTotalPrice,
- reviewTransactionModal: mockReviewTransactionModal,
- });
-
- const defaultEntity = { id: "entity-1", name: "Test Store" };
- const defaultSalePageConfig = { overriddenCohortPriceLevel: null };
-
- beforeEach(() => {
- vi.clearAllMocks();
- mockUseSalesContext.mockReturnValue(defaultSalesContext as any);
- mockUseSalesPaymentContext.mockReturnValue(
- defaultSalesPaymentContext as any,
- );
- mockUseEntitySelected.mockReturnValue([defaultEntity, vi.fn()] as any);
- mockUseSalePageConfig.mockReturnValue(defaultSalePageConfig as any);
-
- // Default pricing - same for cash and credit
- mockTransactionTotalPrice.mockImplementation((options) => {
- const paymentMethodId = options?.paymentMethodId;
- if (paymentMethodId === "cash-1") return 10.0;
- if (paymentMethodId === "cc-1") return 10.0;
- return 10.0; // default
- });
- });
-
- describe("Pricing Display Logic", () => {
- it("shows single price when cash and credit totals are the same", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 2,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Should show single "Pay: $10.00" text
- expect(screen.getByText(/Pay: \$10\.00/)).toBeInTheDocument();
-
- // Should NOT show cash/credit icons when prices are the same
- const svgElements = document.querySelectorAll('svg[aria-hidden="true"]');
- expect(svgElements).toHaveLength(0);
- });
-
- it("shows dual pricing when cash and credit totals differ", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 2,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- // Mock different prices for cash vs credit
- mockTransactionTotalPrice.mockImplementation((options) => {
- const paymentMethodId = options?.paymentMethodId;
- if (paymentMethodId === "cash-1") return 10.0;
- if (paymentMethodId === "cc-1") return 10.5; // Credit has surcharge
- return 10.0; // default
- });
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Should show both cash and credit prices in the payment button area
- // Use getAllByText to handle multiple instances and check the payment button specifically
- const cashPrices = screen.getAllByText("$10.00");
- const creditPrices = screen.getAllByText("$10.50");
-
- // Should have cash price in subtotal AND payment button
- expect(cashPrices.length).toBeGreaterThanOrEqual(1);
- // Should have credit price in payment button
- expect(creditPrices).toHaveLength(1);
-
- // Should show both icons (SVGs with aria-hidden)
- const svgElements = document.querySelectorAll('svg[aria-hidden="true"]');
- expect(svgElements).toHaveLength(2); // Cash and credit card icons
- });
-
- it("calls transactionTotalPrice with correct payment forms", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 2,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Should call transactionTotalPrice for cash, credit, and default
- expect(mockTransactionTotalPrice).toHaveBeenCalledWith({
- paymentMethodId: "cash-1",
- });
- expect(mockTransactionTotalPrice).toHaveBeenCalledWith({
- paymentMethodId: "cc-1",
- });
- expect(mockTransactionTotalPrice).toHaveBeenCalledWith(); // default call
- });
-
- it("shows loading state when calculating background payment method totals", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 2,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesContext.mockReturnValue({
- ...defaultSalesContext,
- } as any);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- isCalculatingBackgroundPaymentMethodTotals: true,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Should show loading spinner and current price
- expect(screen.getByText(/Pay: \$10\.00/)).toBeInTheDocument();
-
- // Should show loading spinner (div with animate-spin class)
- const spinner = document.querySelector(".animate-spin");
- expect(spinner).toBeInTheDocument();
- });
- });
-
- describe("Transaction Totals Calculation", () => {
- it("calculates totals correctly from transaction items", () => {
- const transactionItems = [
- {
- price: 10.0,
- quantity: 2,
- discount: 1.0,
- bottleFee: 0.1,
- environmentFee: 0.05,
- tax: 1.5,
- },
- {
- price: 5.0,
- quantity: 1,
- discount: 0.5,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0.4,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Subtotal: (10*2 - 1) + (5*1 - 0.5) = 19 + 4.5 = 23.5
- expect(screen.getByText("$23.50")).toBeInTheDocument();
-
- // Total Discount: 1.00 + 0.50 = 1.50 (displayed as negative in UI)
- expect(screen.getByText("-$1.50")).toBeInTheDocument();
-
- // Total Fees: 0.10 + 0.05 + 0 + 0 = 0.15
- expect(screen.getByText("$0.15")).toBeInTheDocument();
-
- // Total Tax: 1.50 + 0.40 = 1.90
- expect(screen.getByText("$1.90")).toBeInTheDocument();
- });
-
- it("handles negative quantities correctly", () => {
- const transactionItems = [
- {
- price: 10.0,
- quantity: -1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- // Button should have requires="pos:sell-negative-quantity" permission
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toHaveAttribute("requires", "pos:sell-negative-quantity");
- });
- });
-
- describe("Button States", () => {
- it("disables button when no transaction items", () => {
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems: [],
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toBeDisabled();
- });
-
- it("disables button when cart pricing error", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesContext.mockReturnValue({
- ...defaultSalesContext,
- } as any);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- isGetCartPricingError: true,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toBeDisabled();
- });
-
- it("shows loading state when review transaction modal pending", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- reviewTransactionModalPending: true,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toHaveAttribute("data-loading", "true");
- });
-
- it("shows loading state when credit card payment pending", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- creditCardPaidPending: true,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toHaveAttribute("data-loading", "true");
- });
-
- it("shows green color scheme for positive totals", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockTransactionTotalPrice.mockReturnValue(10.0);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toHaveAttribute("data-color-scheme", "green");
- });
-
- it("shows red color scheme for negative totals", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: -2,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockTransactionTotalPrice.mockReturnValue(-10.0);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- expect(button).toHaveAttribute("data-color-scheme", "red");
- });
-
- it("opens review transaction modal when clicked", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- const button = screen.getByTestId("sale-pay-btn");
- fireEvent.click(button);
-
- expect(mockReviewTransactionModal.onOpen).toHaveBeenCalledTimes(1);
- });
- });
-
- describe("Price Level Override", () => {
- it("shows price level override warning when overridden", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalePageConfig.mockReturnValue({
- overriddenCohortPriceLevel: "WHOLESALE",
- } as any);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- expect(screen.getByText("⚠️ Price level overridden")).toBeInTheDocument();
- });
-
- it("does not show price level override warning when not overridden", () => {
- const transactionItems = [
- {
- price: 5.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- expect(
- screen.queryByText("⚠️ Price level overridden"),
- ).not.toBeInTheDocument();
- });
- });
-
- describe("Edge Cases", () => {
- it("handles zero totals correctly", () => {
- const transactionItems = [
- {
- price: 0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockTransactionTotalPrice.mockReturnValue(0);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- expect(screen.getByText("Pay: $0.00")).toBeInTheDocument();
- });
-
- it("formats large numbers correctly", () => {
- const transactionItems = [
- {
- price: 1000.0,
- quantity: 1,
- discount: 0,
- bottleFee: 0,
- environmentFee: 0,
- tax: 0,
- },
- ];
-
- mockTransactionTotalPrice.mockReturnValue(1234.56);
-
- mockUseSalesPaymentContext.mockReturnValue({
- ...defaultSalesPaymentContext,
- transactionItems,
- } as any);
-
- render(<TotalSummaryCard />);
-
- expect(screen.getByText("Pay: $1,234.56")).toBeInTheDocument();
- });
- });
-});
diff --git a/src/components/SalesScreenComponents/TotalSummaryCard.tsx b/src/components/SalesScreenComponents/TotalSummaryCard.tsx
index 8fafa6e1..76fc4a73 100644
--- a/src/components/SalesScreenComponents/TotalSummaryCard.tsx
+++ b/src/components/SalesScreenComponents/TotalSummaryCard.tsx
@@ -1,32 +1,23 @@
import { Divider, HStack, Text, VStack, useDisclosure } from "@chakra-ui/react";
import { PermissionedButton } from "components/Auth/PermissionedButton";
+import { useSalesContext } from "context/Sales/SalesContext";
import { useMemo } from "react";
-import { FaCreditCard, FaMoneyBillWave } from "react-icons/fa";
-import { useEntitySelected } from "src/context/EntityProvider";
import { useSalesPaymentContext } from "src/context/Sales/SalesPaymentContext";
-import { TransactionPaymentForm } from "src/spring-generated";
-import { currencyFormat, formatPriceAbsolute } from "src/utils/currencyUtils";
+import { currencyFormat } from "src/utils/currencyUtils";
import { useDebounceValue } from "usehooks-ts";
import { FinishTransacationPaymentModal } from "../TransactionsComponents/FinishTransactionPaymentModal";
-import { useSalePageConfig } from "./SalePageConfigProvider";
export const TotalSummaryCard = () => {
+ const { isGetCartPricingError, isCalculatingCartPrice } = useSalesContext();
const {
- isGetCartPricingError,
- isCalculatingCartPrice,
- isCalculatingBackgroundPaymentMethodTotals,
- paymentMethodTypeToPaymentMethod,
- findBestPaymentMethod,
transactionTotalPrice,
transactionItems,
reviewTransactionModal,
reviewTransactionModalPending,
creditCardPaidPending,
- salesChannel,
} = useSalesPaymentContext();
- const [entity] = useEntitySelected();
- const { overriddenCohortPriceLevel } = useSalePageConfig();
const finishPaymentDisclosure = useDisclosure();
+
const totals = useMemo(() => {
return transactionItems.reduce(
(acc, item) => ({
@@ -63,46 +54,6 @@ export const TotalSummaryCard = () => {
300,
);
- // Get cash and credit card totals
- const paymentTotals = useMemo(() => {
- const defaultPaymentMethodId = salesChannel?.defaultPaymentMethodId;
-
- const cashPaymentMethods =
- paymentMethodTypeToPaymentMethod[TransactionPaymentForm.CASH];
- const cashPaymentMethod = findBestPaymentMethod(
- cashPaymentMethods,
- defaultPaymentMethodId,
- );
- const cashPaymentMethodId = cashPaymentMethod?.id;
-
- const creditCardPaymentMethods =
- paymentMethodTypeToPaymentMethod[TransactionPaymentForm["CREDIT CARD"]];
- const creditCardPaymentMethod = findBestPaymentMethod(
- creditCardPaymentMethods,
- defaultPaymentMethodId,
- );
- const creditCardPaymentMethodId = creditCardPaymentMethod?.id;
-
- const cashTotal = transactionTotalPrice({
- paymentMethodId: cashPaymentMethodId,
- });
- const creditCardTotal = transactionTotalPrice({
- paymentMethodId: creditCardPaymentMethodId,
- });
- const defaultTotal = transactionTotalPrice();
- return {
- cash: cashTotal,
- credit: creditCardTotal,
- default: defaultTotal,
- hasSamePrice: Math.abs(cashTotal - creditCardTotal) < 0.01,
- };
- }, [
- transactionTotalPrice,
- paymentMethodTypeToPaymentMethod,
- salesChannel?.defaultPaymentMethodId,
- findBestPaymentMethod,
- ]);
-
return (
<>
<VStack m={2}>
@@ -148,76 +99,13 @@ export const TotalSummaryCard = () => {
debouncedIsCalculatingCartPrice
}
onClick={reviewTransactionModal.onOpen}
- className="w-full min-h-[120px] py-4 px-4 text-3xl"
+ className="w-full h-28 text-3xl"
data-testid="sale-pay-btn"
>
- <div className="flex flex-col items-center justify-center h-full w-full gap-4">
- {/* Price Display with Morphing Container */}
- <div
- className="relative overflow-hidden transition-all duration-300 ease-in-out flex items-center justify-center"
- style={{
- minWidth: isCalculatingBackgroundPaymentMethodTotals
- ? "300px"
- : paymentTotals.hasSamePrice
- ? "200px"
- : "400px",
- }}
- >
- <div
- className={`flex items-center justify-center transition-all duration-300`}
- >
- {isCalculatingBackgroundPaymentMethodTotals ? (
- // Loading state - show current price with spinner
- <div className="flex items-center gap-3">
- <div className="text-3xl font-semibold">
- {"Pay" +
- (transactionItems?.length > 0
- ? ": " + formatPriceAbsolute(paymentTotals.default)
- : "")}
- </div>
- <div className="w-5 h-5 border-2 border-current border-t-transparent rounded-full animate-spin" />
- </div>
- ) : paymentTotals.hasSamePrice ? (
- // Single price
- <div className="text-3xl font-semibold">
- {"Pay" +
- (transactionItems?.length > 0
- ? ": " + formatPriceAbsolute(paymentTotals.default)
- : "")}
- </div>
- ) : (
- // Dual price with smooth entrance
- <div className="flex items-center gap-8 animate-in fade-in duration-300">
- {/* Cash Price */}
- <div className="flex items-center gap-3">
- <FaMoneyBillWave className="w-6 h-6" aria-hidden="true" />
- <div className="text-3xl font-semibold">
- {formatPriceAbsolute(paymentTotals.cash)}
- </div>
- </div>
-
- {/* Separator */}
- <div className="w-px h-8 bg-current opacity-30" />
-
- {/* Credit Price */}
- <div className="flex items-center gap-3">
- <FaCreditCard className="w-6 h-6" aria-hidden="true" />
- <div className="text-3xl font-semibold">
- {formatPriceAbsolute(paymentTotals.credit)}
- </div>
- </div>
- </div>
- )}
- </div>
- </div>
-
- {/* Price Level Override Note */}
- {overriddenCohortPriceLevel && (
- <div className="text-sm opacity-90 text-center">
- ⚠️ Price level overridden
- </div>
- )}
- </div>
+ Pay
+ {transactionItems.length > 0
+ ? `: ${currencyFormat("USD", transactionTotalPrice())}`
+ : ""}
</PermissionedButton>
</VStack>
<FinishTransacationPaymentModal {...finishPaymentDisclosure} />
diff --git a/src/components/SubscriptionBanner.tsx b/src/components/SubscriptionBanner.tsx
deleted file mode 100644
index 31f7fda7..00000000
--- a/src/components/SubscriptionBanner.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { AlertTriangle } from "lucide-react";
-import { useNavigate } from "react-router-dom";
-import { Button } from "./ui/button";
-import { Card, CardContent } from "./ui/card";
-
-export const SubscriptionBanner = ({
- disablePayNow,
-}: {
- disablePayNow: boolean;
-}) => {
- const navigate = useNavigate();
-
- const handlePayNow = () => {
- navigate("/settings/?tab=about-store");
- };
-
- return (
- <div className="fixed top-8 left-1/2 transform -translate-x-1/2 z-50 max-w-md">
- <Card className="border-red-200 bg-red-50 shadow-xl">
- <CardContent className="p-3">
- <div className="flex items-center gap-2">
- <AlertTriangle className="h-4 w-4 text-red-600 flex-shrink-0" />
- <p className="text-sm text-red-700 leading-relaxed flex-1">
- Your subscription payment is overdue.
- </p>
- <Button
- onClick={handlePayNow}
- variant="default"
- size="sm"
- className="bg-red-500 hover:bg-red-400 text-white font-semibold shadow-md hover:shadow-lg transition-all duration-200 rounded-lg px-4 py-0.5 text-sm h-6"
- disabled={disablePayNow}
- >
- Pay
- </Button>
- </div>
- </CardContent>
- </Card>
- </div>
- );
-};
diff --git a/src/components/SubscriptionBannerWrapper.tsx b/src/components/SubscriptionBannerWrapper.tsx
deleted file mode 100644
index f36111af..00000000
--- a/src/components/SubscriptionBannerWrapper.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useEntity } from "context/EntityProvider";
-import { usePermissions } from "context/PermissionsContext";
-import { useMemo } from "react";
-import { useGetEntitySubscriptionStatus } from "src/spring-generated/hooks/useGetEntitySubscriptionStatus";
-import { SubscriptionBanner } from "./SubscriptionBanner";
-
-const badSubscriptionStatuses = new Set([
- "past_due",
- "unpaid",
- "incomplete",
- "incomplete_expired",
-]);
-
-export const SubscriptionBannerWrapper = () => {
- const [entity] = useEntity();
- const { hasPermission } = usePermissions();
- const hasSubscriptionReadStatusPermission =
- hasPermission("esub/*:read_status");
- const hasSubscriptionReadPaymentLinkPermission = hasPermission(
- "esub/*:read_payment_link",
- );
- const { data: subscriptionStatus } = useGetEntitySubscriptionStatus(
- {
- entityId: entity?.id ?? 0,
- },
- {
- query: {
- enabled: !!entity?.id && hasSubscriptionReadStatusPermission,
- queryKey: ["entitySubscriptionStatus", entity?.id],
- throwOnError: false,
- },
- },
- );
-
- // Determine if subscription is unpaid
- const isSubscriptionUnpaid = useMemo(
- () =>
- subscriptionStatus &&
- badSubscriptionStatuses.has(subscriptionStatus.toLowerCase()),
- [subscriptionStatus],
- );
-
- const shouldShowBanner = useMemo(
- () =>
- isSubscriptionUnpaid && entity?.id && hasSubscriptionReadStatusPermission,
- [isSubscriptionUnpaid, entity?.id, hasSubscriptionReadStatusPermission],
- );
-
- if (!shouldShowBanner) {
- return null;
- }
-
- return (
- <SubscriptionBanner
- disablePayNow={!hasSubscriptionReadPaymentLinkPermission}
- />
- );
-};
diff --git a/src/components/SubscriptionStatusBadge.tsx b/src/components/SubscriptionStatusBadge.tsx
deleted file mode 100644
index c4bf5a2f..00000000
--- a/src/components/SubscriptionStatusBadge.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import { cn } from "../lib/utils";
-import { Badge } from "./ui/badge";
-
-type SubscriptionStatus =
- | "incomplete"
- | "incomplete_expired"
- | "trialing"
- | "active"
- | "past_due"
- | "canceled"
- | "unpaid"
- | "paused";
-
-interface SubscriptionStatusBadgeProps {
- status: SubscriptionStatus | string;
- className?: string;
-}
-
-const getStatusConfig = (status: string) => {
- const normalizedStatus = status.toLowerCase();
-
- switch (normalizedStatus) {
- case "active":
- return {
- label: "Active",
- variant: "default" as const,
- className:
- "bg-green-100 text-green-800 border-green-200 hover:bg-green-200",
- };
- case "trialing":
- return {
- label: "Trialing",
- variant: "secondary" as const,
- className:
- "bg-blue-100 text-blue-800 border-blue-200 hover:bg-blue-200",
- };
- case "past_due":
- return {
- label: "Past Due",
- variant: "destructive" as const,
- className: "bg-red-100 text-red-800 border-red-200 hover:bg-red-200",
- };
- case "unpaid":
- return {
- label: "Unpaid",
- variant: "destructive" as const,
- className: "bg-red-100 text-red-800 border-red-200 hover:bg-red-200",
- };
- case "incomplete":
- return {
- label: "Incomplete",
- variant: "outline" as const,
- className:
- "bg-yellow-100 text-yellow-800 border-yellow-200 hover:bg-yellow-200",
- };
- case "incomplete_expired":
- return {
- label: "Incomplete Expired",
- variant: "destructive" as const,
- className: "bg-red-100 text-red-800 border-red-200 hover:bg-red-200",
- };
- case "canceled":
- return {
- label: "Canceled",
- variant: "secondary" as const,
- className:
- "bg-gray-100 text-gray-800 border-gray-200 hover:bg-gray-200",
- };
- case "paused":
- return {
- label: "Paused",
- variant: "outline" as const,
- className:
- "bg-orange-100 text-orange-800 border-orange-200 hover:bg-orange-200",
- };
- default:
- return {
- label: status,
- variant: "outline" as const,
- className:
- "bg-gray-100 text-gray-600 border-gray-200 hover:bg-gray-200",
- };
- }
-};
-
-export const SubscriptionStatusBadge = ({
- status,
- className,
-}: SubscriptionStatusBadgeProps) => {
- const config = getStatusConfig(status);
-
- return (
- <Badge
- variant={config.variant}
- className={cn(
- "font-medium text-xs px-2 py-1 border",
- config.className,
- className,
- )}
- >
- {config.label}
- </Badge>
- );
-};
diff --git a/src/components/Table/AddRow/AddRow.tsx b/src/components/Table/AddRow/AddRow.tsx
index 6272ab4b..e292f99a 100644
--- a/src/components/Table/AddRow/AddRow.tsx
+++ b/src/components/Table/AddRow/AddRow.tsx
@@ -37,17 +37,14 @@ export function AddRow<Data>({
if (newRow) {
const onMouseEnter = () => setIsHovering(true);
const onMouseLeave = () => setIsHovering(false);
- const currentPortalRef = portalRef.current;
- currentPortalRef.addEventListener("mouseenter", onMouseEnter);
- currentPortalRef.addEventListener("mouseleave", onMouseLeave);
+ portalRef.current.addEventListener("mouseenter", onMouseEnter);
+ portalRef.current.addEventListener("mouseleave", onMouseLeave);
return () => {
- currentPortalRef.removeEventListener("mouseenter", onMouseEnter);
- currentPortalRef.removeEventListener("mouseleave", onMouseLeave);
+ portalRef.current?.removeEventListener("mouseenter", onMouseEnter);
+ portalRef.current?.removeEventListener("mouseleave", onMouseLeave);
};
}
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [portalRef?.current, newRow]);
return (
diff --git a/src/components/TagSummary.tsx b/src/components/TagSummary.tsx
index cdefa2f6..5f5b99fe 100644
--- a/src/components/TagSummary.tsx
+++ b/src/components/TagSummary.tsx
@@ -170,7 +170,6 @@ const TagSummary = ({
),
}),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[hasPermission, isPrinting],
);
diff --git a/src/components/TransactionByDate.tsx b/src/components/TransactionByDate.tsx
index fcf054b6..3b4b2ac0 100644
--- a/src/components/TransactionByDate.tsx
+++ b/src/components/TransactionByDate.tsx
@@ -135,7 +135,6 @@ const TransactionByDate = ({
),
}),
];
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
totals?.bottleDeposit,
totals?.discount,
diff --git a/src/components/TransactionDetail/DecisionDetailsDrawer.tsx b/src/components/TransactionDetail/DecisionDetailsDrawer.tsx
deleted file mode 100644
index 61797b1e..00000000
--- a/src/components/TransactionDetail/DecisionDetailsDrawer.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import { Badge } from "components/ui/badge";
-import { Button } from "components/ui/button";
-import {
- Drawer,
- DrawerClose,
- DrawerContent,
- DrawerDescription,
- DrawerFooter,
- DrawerHeader,
- DrawerTitle,
-} from "components/ui/drawer";
-import { useUserAuth } from "context/AuthenticationContext/AuthenticationContext";
-import { useEntitySelected } from "context/EntityProvider";
-import { useRegisterProvider } from "context/RegisterProvider";
-import { useOrderItemDecisionUpdater } from "hooks/useOrderItemDecisionUpdater";
-import { DbOrderItemDecision } from "src/phoenix-generated";
-
-interface DecisionDetailsDrawerProps {
- isOpen: boolean;
- onClose: () => void;
- decision: DbOrderItemDecision | null;
- onDecisionUpdated?: () => void;
-}
-
-const getDecisionStatusBadge = (status: string) => {
- switch (status.toUpperCase()) {
- case "ACCEPTED":
- return <Badge variant="successful">Accepted</Badge>;
- case "REJECTED":
- return <Badge variant="destructive">Rejected</Badge>;
- case "CREATED":
- return <Badge variant="pending">Pending</Badge>;
- default:
- return <Badge variant="outline">{status}</Badge>;
- }
-};
-
-export const DecisionDetailsDrawer: React.FC<DecisionDetailsDrawerProps> = ({
- isOpen,
- onClose,
- decision,
- onDecisionUpdated,
-}) => {
- const { user } = useUserAuth();
- const [entity] = useEntitySelected();
- const { register } = useRegisterProvider();
- const { updateDecisions, isUpdating } = useOrderItemDecisionUpdater({
- onSuccess: () => {
- onDecisionUpdated?.();
- onClose();
- },
- });
-
- const handleStatusUpdate = async (status: "ACCEPTED" | "REJECTED") => {
- if (!decision || !user?.uid) return;
-
- await updateDecisions([
- {
- decisionId: decision.id,
- status,
- userId: user?.uid,
- source: `${entity.id.toString()} register:${register.registerNumber?.toString() ?? "unknown"}`,
- },
- ]);
- };
-
- if (!decision) return null;
-
- const isPending = decision.status.toUpperCase() === "CREATED";
- const metadata = decision.metadata;
- const notes = metadata?.customerNotes || metadata?.internalNotes;
-
- return (
- <Drawer open={isOpen} onOpenChange={(open) => !open && onClose()}>
- <DrawerContent>
- <DrawerHeader>
- <DrawerTitle>Decision Details</DrawerTitle>
- <DrawerDescription>
- Transaction Item ID: {decision.transactionItemId}
- </DrawerDescription>
- </DrawerHeader>
-
- <div className="px-4 space-y-4">
- <div className="flex items-center gap-2">
- <span className="font-medium">Status:</span>
- {getDecisionStatusBadge(decision.status)}
- </div>
-
- <div className="flex items-center gap-2">
- <span className="font-medium">Decision Time:</span>
- <span>
- {decision.decisionTime
- ? new Date(decision.decisionTime).toLocaleString()
- : "-"}
- </span>
- </div>
-
- {decision.reason && (
- <div className="space-y-1">
- <span className="font-medium">Reason:</span>
- <p className="text-sm text-gray-600">{decision.reason}</p>
- </div>
- )}
-
- {notes && (
- <div className="space-y-1">
- <span className="font-medium">Notes:</span>
- <p className="text-sm text-gray-600">{notes}</p>
- </div>
- )}
- </div>
-
- <DrawerFooter>
- <div className="flex gap-2">
- {isPending && (
- <>
- <Button
- variant="outline"
- disabled={isUpdating}
- onClick={() => handleStatusUpdate("ACCEPTED")}
- className="flex-1"
- >
- Accept
- </Button>
- <Button
- variant="destructive"
- disabled={isUpdating}
- onClick={() => handleStatusUpdate("REJECTED")}
- className="flex-1"
- >
- Reject
- </Button>
- </>
- )}
- <DrawerClose asChild>
- <Button variant="secondary" className="flex-1">
- Close
- </Button>
- </DrawerClose>
- </div>
- </DrawerFooter>
- </DrawerContent>
- </Drawer>
- );
-};
diff --git a/src/components/TransactionDetail/TransactionItemsTable.tsx b/src/components/TransactionDetail/TransactionItemsTable.tsx
index ba4046cc..d875527c 100644
--- a/src/components/TransactionDetail/TransactionItemsTable.tsx
+++ b/src/components/TransactionDetail/TransactionItemsTable.tsx
@@ -1,110 +1,28 @@
import { createColumnHelper } from "@tanstack/react-table";
import { TransformityDataTable } from "components/Table/TransformityDataTable";
-import { Badge } from "components/ui/badge";
-import { Button } from "components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "components/ui/popover";
import { useEntitySelected } from "context/EntityProvider";
import { usePermissions } from "context/PermissionsContext";
import { TransactionDataOutput } from "generated/types";
import { TriangleAlert } from "lucide-react";
-import { useMemo, useState } from "react";
+import { useMemo } from "react";
import { Link } from "react-router-dom";
-import { DbOrderItemDecision } from "src/phoenix-generated";
import { currencyFormat } from "utils/currencyUtils";
-import { DecisionDetailsDrawer } from "./DecisionDetailsDrawer";
interface TransactionItemsTableProps {
items: TransactionDataOutput[];
- orderItemDecisions?: DbOrderItemDecision[];
- selectedRows?: Set<number>;
- onRowSelect?: (itemId: number, isSelected: boolean) => void;
- onSelectAll?: (isSelected: boolean) => void;
- onDecisionUpdated?: () => void;
}
const columnHelper = createColumnHelper<TransactionDataOutput>();
-const getDecisionStatusBadge = (status: string) => {
- switch (status.toUpperCase()) {
- case "ACCEPTED":
- return <Badge variant="successful">Accepted</Badge>;
- case "REJECTED":
- return <Badge variant="destructive">Rejected</Badge>;
- case "CREATED":
- return <Badge variant="pending">Pending</Badge>;
- default:
- return <Badge variant="outline">{status}</Badge>;
- }
-};
-
export const TransactionItemsTable = ({
items,
- orderItemDecisions = [],
- selectedRows = new Set(),
- onRowSelect,
- onSelectAll,
- onDecisionUpdated,
}: TransactionItemsTableProps) => {
const [entity] = useEntitySelected();
const { hasPermission } = usePermissions();
- const [selectedDecision, setSelectedDecision] =
- useState<DbOrderItemDecision | null>(null);
- const [isDrawerOpen, setIsDrawerOpen] = useState(false);
-
- // Create a map for quick lookup of decisions by transaction item ID
- const decisionMap = useMemo(() => {
- const map = new Map<number, DbOrderItemDecision>();
- orderItemDecisions.forEach((decision) => {
- map.set(decision.transactionItemId, decision);
- });
- return map;
- }, [orderItemDecisions]);
-
- const hasOrderDecisions = orderItemDecisions.length > 0;
- const handleDecisionClick = (decision: DbOrderItemDecision) => {
- setSelectedDecision(decision);
- setIsDrawerOpen(true);
- };
-
- const handleDrawerClose = () => {
- setIsDrawerOpen(false);
- setSelectedDecision(null);
- };
-
- const columns = useMemo(
- () => [
- // Add checkbox column if there are order decisions
- ...(hasOrderDecisions && onRowSelect
- ? [
- columnHelper.display({
- id: "select",
- header: () => (
- <input
- type="checkbox"
- checked={
- selectedRows.size === items.length && items.length > 0
- }
- onChange={(e) => {
- const isSelected = e.target.checked;
- onSelectAll?.(isSelected);
- }}
- className="rounded border-gray-300"
- />
- ),
- cell: ({ row }) => (
- <input
- type="checkbox"
- checked={selectedRows.has(row.original.id)}
- onChange={(e) => {
- onRowSelect(row.original.id, e.target.checked);
- }}
- className="rounded border-gray-300"
- />
- ),
- }),
- ]
- : []),
+ const columns = useMemo(() => {
+ const cols = [
columnHelper.accessor("name", {
cell: ({ row, getValue }) => (
<Link
@@ -158,72 +76,34 @@ export const TransactionItemsTable = ({
header: "Item total",
cell: ({ getValue }) => currencyFormat("USD", getValue()),
}),
- ...(hasPermission("item/*:stats", [entity.id])
- ? [
- columnHelper.accessor("grossProfit", {
- header: "Profit margin",
- cell: ({ getValue }) => {
- const value = getValue();
- return value ? (value * 100).toFixed(2) + "%" : "-";
- },
- }),
- ]
- : []),
- ...(hasOrderDecisions && onRowSelect && onSelectAll
- ? [
- columnHelper.display({
- id: "decisionStatus",
- header: "Decision",
- cell: ({ row }) => {
- const decision = decisionMap.get(row.original.id);
- if (!decision) return null;
+ ];
- return (
- <div className="flex items-center gap-2">
- {getDecisionStatusBadge(decision.status)}
- <Button
- variant="outline"
- size="sm"
- onClick={() => handleDecisionClick(decision)}
- >
- View Details
- </Button>
- </div>
- );
- },
- }),
- ]
- : []),
- ],
- [
- hasOrderDecisions,
- onRowSelect,
- onSelectAll,
- hasPermission,
- entity.id,
- selectedRows,
- items.length,
- decisionMap,
- ],
- );
+ if (hasPermission("item/*:stats", [entity.id])) {
+ cols.splice(
+ 5,
+ 0,
+ columnHelper.accessor("grossProfit", {
+ header: "Profit margin",
+ cell: ({ getValue }) => {
+ const value = getValue();
+ return value ? (value * 100).toFixed(2) + "%" : "-";
+ },
+ }) as unknown as any,
+ );
+ }
+
+ return cols;
+ }, [entity.id, hasPermission]);
return (
- <>
- <TransformityDataTable
- data={items}
- columns={columns}
- containerProps={{
- width: "100%",
- }}
- variant="pretty"
- isV2Header
- />
- <DecisionDetailsDrawer
- isOpen={isDrawerOpen}
- onClose={handleDrawerClose}
- decision={selectedDecision}
- onDecisionUpdated={onDecisionUpdated}
- />
- </>
+ <TransformityDataTable
+ data={items}
+ columns={columns}
+ containerProps={{
+ width: "100%",
+ }}
+ variant="pretty"
+ isV2Header
+ />
);
};
diff --git a/src/components/TransactionsComponents/useTransactionReceipt.tsx b/src/components/TransactionsComponents/useTransactionReceipt.tsx
index b4a8a2f0..c9bd258e 100644
--- a/src/components/TransactionsComponents/useTransactionReceipt.tsx
+++ b/src/components/TransactionsComponents/useTransactionReceipt.tsx
@@ -58,10 +58,6 @@ export const useTransactionReceipt = () => {
EntityConfigKey.RECEIPT_BOTTOM_TEXT,
"",
);
- const { value: showCashierOnReceipt } = useEntityConfig(
- EntityConfigKey.SHOW_CASHIER_ON_RECEIPT,
- true,
- );
const downloadAssetLinkMutation = useGetDownloadAssetLink();
const printReceipt = useCallback(
@@ -98,7 +94,7 @@ export const useTransactionReceipt = () => {
);
const receiptJSX = shortReceiptConfig ? (
- <Printer width={printerWidth} className="mx-auto" type="star">
+ <Printer width={printerWidth} type="star">
{logoUrl && (
<Image crossOrigin="anonymous" src={logoUrl} align="center" />
)}
@@ -163,14 +159,12 @@ export const useTransactionReceipt = () => {
: "UNKNOWN"}
</Text>
)}
- {showCashierOnReceipt && (
- <Text align="center">
- CASHIER:{" "}
- {transactionOutput.completedByName
- ? `${transactionOutput.completedByName.split(" ")?.[0]}`
- : `-`}
- </Text>
- )}
+ <Text>
+ CASHIER:{" "}
+ {transactionOutput.completedByName
+ ? `${transactionOutput.completedByName.split(" ")?.[0]}`
+ : `-`}
+ </Text>
{transactionOutput.transactionItems.map((itemDetail, index) => {
return (
<Fragment key={index}>
@@ -292,13 +286,22 @@ export const useTransactionReceipt = () => {
)}
/>
)}
+ {entity.surchargeFee && !!transactionOutput.creditCardFee && (
+ <Row
+ left="PAYMENT PROCESSING FEE:"
+ right={USDollar.format(transactionOutput.creditCardFee)}
+ />
+ )}
<Row
left={"TOTAL"}
right={USDollar.format(
transactionOutput.transactionItems.reduce(
(prev, a) => prev + a.totalPrice,
0,
- ),
+ ) +
+ (entity.surchargeFee
+ ? (transactionOutput.creditCardFee ?? 0)
+ : 0),
)}
/>
<Line />
@@ -442,7 +445,7 @@ export const useTransactionReceipt = () => {
<Cut />
</Printer>
) : (
- <Printer width={printerWidth} className="mx-auto" type="star">
+ <Printer width={printerWidth} type="star">
{entity.id === 12 && (
<Image src="https://store-logos-public-prod.s3.amazonaws.com/Contislogo.png" />
)}
@@ -512,14 +515,6 @@ export const useTransactionReceipt = () => {
: "UNKNOWN"}
</Text>
)}
- {showCashierOnReceipt && (
- <Text align="center">
- CASHIER:{" "}
- {transactionOutput.completedByName
- ? `${transactionOutput.completedByName.split(" ")?.[0]}`
- : `-`}
- </Text>
- )}
{transactionOutput.transactionItems.map((itemDetail, index) => {
return (
<Fragment key={index}>
@@ -739,21 +734,18 @@ export const useTransactionReceipt = () => {
void sendReceiptData(receiptJSX);
},
[
- queryClient,
- loyaltyProgramId,
- downloadAssetLinkMutation,
- receiptLogo,
+ departmentKeyMap,
+ entity.address,
entity.id,
entity.name,
- entity.address,
entity.phoneNumber,
- logoUrlFallback,
- shortReceiptConfig,
+ loyaltyProgramId,
printerWidth,
- showCashierOnReceipt,
+ queryClient,
receiptBottomText,
sendReceiptData,
- departmentKeyMap,
+ shortReceiptConfig,
+ entity.surchargeFee,
],
);
diff --git a/src/components/UnauthenticatedUserOnlyRoute.tsx b/src/components/UnauthenticatedUserOnlyRoute.tsx
index ec9b0483..af81a4e6 100644
--- a/src/components/UnauthenticatedUserOnlyRoute.tsx
+++ b/src/components/UnauthenticatedUserOnlyRoute.tsx
@@ -1,9 +1,9 @@
import { useUserAuth } from "context/AuthenticationContext/AuthenticationContext";
-import type { FC } from "react";
+import React from "react";
import { Navigate, Outlet } from "react-router-dom";
import Loading from "./Loading";
-const UnauthenticatedUserOnlyRoute: FC = () => {
+const UnauthenticatedUserOnlyRoute: React.FC<{}> = () => {
const { user } = useUserAuth();
if (user === undefined) {
@@ -11,7 +11,7 @@ const UnauthenticatedUserOnlyRoute: FC = () => {
} else if (user === null) {
return <Outlet />;
} else {
- return <Navigate to="/register/open/" />;
+ return <Navigate to="/sale/" />;
}
};
diff --git a/src/components/__tests__/DatabaseSyncLoader.test.tsx b/src/components/__tests__/DatabaseSyncLoader.test.tsx
deleted file mode 100644
index 5f6b4cbe..00000000
--- a/src/components/__tests__/DatabaseSyncLoader.test.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import { act, render, screen } from "@testing-library/react";
-import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
-import { DatabaseSyncLoader } from "../DatabaseSyncLoader";
-
-// Mock the cn utility function
-vi.mock("../lib/utils", () => ({
- cn: vi.fn((...classes) => classes.filter(Boolean).join(" ")),
-}));
-
-describe("DatabaseSyncLoader", () => {
- beforeEach(() => {
- vi.clearAllMocks();
- // Mock timers for testing animations
- vi.useFakeTimers();
- });
-
- afterEach(() => {
- vi.useRealTimers();
- });
-
- it("should render with default props", () => {
- render(<DatabaseSyncLoader />);
-
- expect(screen.getByText(/Syncing database/)).toBeInTheDocument();
- expect(
- screen.getByText("Please wait while we prepare your data"),
- ).toBeInTheDocument();
- expect(screen.getByText("Transformity Database")).toBeInTheDocument();
- });
-
- it("should render with custom message", () => {
- const customMessage = "Loading inventory data";
- render(<DatabaseSyncLoader message={customMessage} />);
-
- expect(screen.getByText(customMessage)).toBeInTheDocument();
- });
-
- it("should show progress bar when showProgress is true", () => {
- render(<DatabaseSyncLoader showProgress={true} />);
-
- expect(screen.getByText("Syncing")).toBeInTheDocument();
- expect(screen.getByText("0%")).toBeInTheDocument();
-
- // Progress bar container should be present
- const progressContainer = screen.getByText("Syncing").closest("div");
- expect(progressContainer).toBeInTheDocument();
- });
-
- it("should not show progress bar when showProgress is false", () => {
- render(<DatabaseSyncLoader showProgress={false} />);
-
- expect(screen.queryByText("Syncing")).not.toBeInTheDocument();
- expect(screen.queryByText("0%")).not.toBeInTheDocument();
- });
-
- it("should animate dots in loading text", () => {
- render(<DatabaseSyncLoader message="Loading" />);
-
- // Initially no dots
- expect(screen.getByText("Loading")).toBeInTheDocument();
-
- // After 500ms, should have one dot
- act(() => {
- vi.advanceTimersByTime(500);
- });
- expect(screen.getByText("Loading.")).toBeInTheDocument();
-
- // After another 500ms, should have two dots
- act(() => {
- vi.advanceTimersByTime(500);
- });
- expect(screen.getByText("Loading..")).toBeInTheDocument();
-
- // After another 500ms, should have three dots
- act(() => {
- vi.advanceTimersByTime(500);
- });
- expect(screen.getByText("Loading...")).toBeInTheDocument();
-
- // After another 500ms, should reset to no dots
- act(() => {
- vi.advanceTimersByTime(500);
- });
- expect(screen.getByText("Loading")).toBeInTheDocument();
- });
-
- it("should animate progress bar when showProgress is true", () => {
- render(<DatabaseSyncLoader showProgress={true} />);
-
- // Initially 0%
- expect(screen.getByText("0%")).toBeInTheDocument();
-
- // After 3000ms, progress should increase (matches the interval in component)
- act(() => {
- vi.advanceTimersByTime(3000);
- });
-
- // Progress should be greater than 0 but less than or equal to 90
- const progressText = screen.getByText(/%$/);
- const progressValue = parseInt(
- progressText.textContent?.replace("%", "") || "0",
- );
- expect(progressValue).toBeGreaterThan(0);
- expect(progressValue).toBeLessThanOrEqual(90);
- });
-
- it("should cap progress at 90%", () => {
- render(<DatabaseSyncLoader showProgress={true} />);
-
- // Advance time significantly to reach the cap
- act(() => {
- vi.advanceTimersByTime(10000); // 10 seconds
- });
-
- const progressText = screen.getByText(/%$/);
- const progressValue = parseInt(
- progressText.textContent?.replace("%", "") || "0",
- );
- expect(progressValue).toBeLessThanOrEqual(90);
- });
-
- it("should apply custom className", () => {
- const customClass = "custom-loader-class";
- const { container } = render(
- <DatabaseSyncLoader className={customClass} />,
- );
-
- expect(container.firstChild).toHaveClass(customClass);
- });
-
- it("should render database icon", () => {
- const { container } = render(<DatabaseSyncLoader />);
-
- // Check for SVG icon by looking for SVG element
- const svg = container.querySelector("svg");
- expect(svg).toBeInTheDocument();
- expect(screen.getByText("Transformity Database")).toBeInTheDocument();
- });
-
- it("should render spinner elements", () => {
- const { container } = render(<DatabaseSyncLoader />);
-
- // Check for spinner elements by class names
- const spinners = container.querySelectorAll(
- ".animate-spin, .animate-pulse",
- );
- expect(spinners.length).toBeGreaterThan(0);
- });
-
- it("should cleanup timers on unmount", () => {
- const { unmount } = render(<DatabaseSyncLoader showProgress={true} />);
-
- // Start the timers
- act(() => {
- vi.advanceTimersByTime(100);
- });
-
- // Unmount component
- unmount();
-
- // Advance timers after unmount - should not cause errors
- act(() => {
- vi.advanceTimersByTime(1000);
- });
-
- // No errors should be thrown
- expect(true).toBe(true);
- });
-
- it("should handle empty message gracefully", () => {
- render(<DatabaseSyncLoader message="" />);
-
- // Should still render other elements
- expect(
- screen.getByText("Please wait while we prepare your data"),
- ).toBeInTheDocument();
- expect(screen.getByText("Transformity Database")).toBeInTheDocument();
- });
-});
diff --git a/src/components/__tests__/SalePageSyncOverlay.test.tsx b/src/components/__tests__/SalePageSyncOverlay.test.tsx
deleted file mode 100644
index fe47e41e..00000000
--- a/src/components/__tests__/SalePageSyncOverlay.test.tsx
+++ /dev/null
@@ -1,207 +0,0 @@
-import { render, screen } from "@testing-library/react";
-import { beforeEach, describe, expect, it, vi } from "vitest";
-import { SalePageSyncOverlay } from "../SalePageSyncOverlay";
-
-// Mock the dependencies
-vi.mock("../DatabaseSyncLoader", () => ({
- DatabaseSyncLoader: vi.fn(({ message, showProgress, className }) => (
- <div
- data-testid="database-sync-loader"
- data-message={message}
- data-show-progress={showProgress}
- className={className}
- >
- Mocked DatabaseSyncLoader
- </div>
- )),
-}));
-
-vi.mock("../pg-lite/PGliteSyncContext", () => ({
- usePGliteSync: vi.fn(),
-}));
-
-import { DatabaseSyncLoader } from "../DatabaseSyncLoader";
-import { usePGliteSync } from "../pg-lite/PGliteSyncContext";
-
-const mockUsePGliteSync = usePGliteSync as any;
-const MockDatabaseSyncLoader = DatabaseSyncLoader as any;
-
-describe("SalePageSyncOverlay", () => {
- const defaultChildren = <div data-testid="child-content">Test Content</div>;
-
- beforeEach(() => {
- vi.clearAllMocks();
- });
-
- it("should render children when not syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
-
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(screen.getByTestId("child-content")).toBeInTheDocument();
- expect(screen.getByText("Test Content")).toBeInTheDocument();
- expect(
- screen.queryByTestId("database-sync-loader"),
- ).not.toBeInTheDocument();
- });
-
- it("should render sync overlay when syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: true,
- });
-
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(screen.getByTestId("database-sync-loader")).toBeInTheDocument();
- expect(screen.queryByTestId("child-content")).not.toBeInTheDocument();
- });
-
- it("should pass correct props to DatabaseSyncLoader when syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: true,
- });
-
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(MockDatabaseSyncLoader).toHaveBeenCalledWith(
- expect.objectContaining({
- message: "Syncing POS database",
- showProgress: true,
- className: "shadow-lg",
- }),
- expect.any(Object),
- );
- });
-
- it("should render informational text when syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: true,
- });
-
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(
- screen.getByText("We're preparing your point-of-sale system."),
- ).toBeInTheDocument();
- expect(
- screen.getByText("This usually takes just a few moments..."),
- ).toBeInTheDocument();
- });
-
- it("should have correct overlay styling classes when syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: true,
- });
-
- const { container } = render(
- <SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>,
- );
-
- const overlay = container.firstChild as HTMLElement;
- expect(overlay).toHaveClass(
- "fixed",
- "inset-0",
- "z-50",
- "flex",
- "items-center",
- "justify-center",
- );
- expect(overlay).toHaveClass("bg-background/95", "backdrop-blur-sm");
- });
-
- it("should handle multiple children when not syncing", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
-
- const multipleChildren = (
- <>
- <div data-testid="child-1">Child 1</div>
- <div data-testid="child-2">Child 2</div>
- </>
- );
-
- render(<SalePageSyncOverlay>{multipleChildren}</SalePageSyncOverlay>);
-
- expect(screen.getByTestId("child-1")).toBeInTheDocument();
- expect(screen.getByTestId("child-2")).toBeInTheDocument();
- expect(
- screen.queryByTestId("database-sync-loader"),
- ).not.toBeInTheDocument();
- });
-
- it("should handle null children gracefully", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
-
- render(<SalePageSyncOverlay>{null}</SalePageSyncOverlay>);
-
- expect(
- screen.queryByTestId("database-sync-loader"),
- ).not.toBeInTheDocument();
- // Should not throw any errors
- });
-
- it("should handle undefined children gracefully", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
-
- render(<SalePageSyncOverlay>{undefined}</SalePageSyncOverlay>);
-
- expect(
- screen.queryByTestId("database-sync-loader"),
- ).not.toBeInTheDocument();
- // Should not throw any errors
- });
-
- it("should transition correctly from syncing to not syncing", () => {
- const { rerender } = render(
- <SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>,
- );
-
- // Initially syncing
- mockUsePGliteSync.mockReturnValue({
- isSyncing: true,
- });
- rerender(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(screen.getByTestId("database-sync-loader")).toBeInTheDocument();
- expect(screen.queryByTestId("child-content")).not.toBeInTheDocument();
-
- // Stop syncing
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
- rerender(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(
- screen.queryByTestId("database-sync-loader"),
- ).not.toBeInTheDocument();
- expect(screen.getByTestId("child-content")).toBeInTheDocument();
- });
-
- it("should call usePGliteSync hook", () => {
- mockUsePGliteSync.mockReturnValue({
- isSyncing: false,
- });
-
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
-
- expect(mockUsePGliteSync).toHaveBeenCalledTimes(1);
- });
-
- it("should handle sync context errors gracefully", () => {
- // Mock the hook to throw an error
- mockUsePGliteSync.mockImplementation(() => {
- throw new Error("Context not found");
- });
-
- expect(() => {
- render(<SalePageSyncOverlay>{defaultChildren}</SalePageSyncOverlay>);
- }).toThrow("Context not found");
- });
-});
diff --git a/src/components/common/CommandMenuShortcutOverlay.tsx b/src/components/common/CommandMenuShortcutOverlay.tsx
new file mode 100644
index 00000000..ff7855b5
--- /dev/null
+++ b/src/components/common/CommandMenuShortcutOverlay.tsx
@@ -0,0 +1,56 @@
+import { useEffect, useState } from "react";
+
+interface CommandMenuShortcutOverlayProps {
+ /**
+ * Whether to display a transparent overlay that intercepts clicks
+ * Useful for pages with iframes to ensure keyboard shortcuts work
+ */
+ withOverlay?: boolean;
+}
+
+export const CommandMenuShortcutOverlay = ({
+ withOverlay = false,
+}: CommandMenuShortcutOverlayProps) => {
+ const [showOverlay, setShowOverlay] = useState(false);
+
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
+ e.preventDefault();
+ // Dispatch custom event that CommandMenu can listen to
+ window.dispatchEvent(new CustomEvent("commandMenuTrigger"));
+ }
+ };
+
+ const handleIframeLoaded = () => {
+ setShowOverlay(true);
+ };
+
+ document.addEventListener("keydown", handleKeyDown);
+ window.addEventListener("iframeLoaded", handleIframeLoaded);
+
+ return () => {
+ document.removeEventListener("keydown", handleKeyDown);
+ window.removeEventListener("iframeLoaded", handleIframeLoaded);
+ };
+ }, []);
+
+ const handleOverlayClick = () => {
+ // Hide overlay temporarily when user clicks, then show it again
+ // This allows clicks to pass through to the iframe content
+ setShowOverlay(false);
+ setTimeout(() => setShowOverlay(true), 100);
+ };
+
+ if (!withOverlay || !showOverlay) return null;
+
+ return (
+ <div
+ onClick={handleOverlayClick}
+ className="absolute inset-0 bg-transparent z-[1000] pointer-events-auto"
+ tabIndex={0}
+ onFocus={(e) => e.currentTarget.blur()}
+ aria-hidden="true"
+ />
+ );
+};
diff --git a/src/components/common/EmployeePinInput/EmployeePinInput.stories.tsx b/src/components/common/EmployeePinInput/EmployeePinInput.stories.tsx
index 63cb4fc9..5771014c 100644
--- a/src/components/common/EmployeePinInput/EmployeePinInput.stories.tsx
+++ b/src/components/common/EmployeePinInput/EmployeePinInput.stories.tsx
@@ -1,4 +1,4 @@
-import { Meta, StoryObj } from "@storybook/react";
+import { Meta, StoryObj } from "@storybook/react/*";
import { expect, userEvent, waitFor, within } from "@storybook/test";
import { useState } from "react";
import { EmployeePinInput } from "./EmployeePinInput";
diff --git a/src/components/common/EraseDatabaseButton.tsx b/src/components/common/EraseDatabaseButton.tsx
deleted file mode 100644
index 032d0527..00000000
--- a/src/components/common/EraseDatabaseButton.tsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import { usePGlite } from "@electric-sql/pglite-react";
-import { ERASE_OPFS_DB } from "components/pg-lite/PgliteOptions";
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogTrigger,
-} from "components/ui/alert-dialog";
-import { Button } from "components/ui/button";
-import { useToast } from "components/ui/use-toast";
-import { useEntity } from "context/EntityProvider";
-import { Database, Loader2, Trash2 } from "lucide-react";
-import { useState } from "react";
-
-interface EraseDatabaseButtonProps {
- className?: string;
-}
-
-export const EraseDatabaseButton: React.FC<EraseDatabaseButtonProps> = ({
- className,
-}) => {
- const [isErasing, setIsErasing] = useState(false);
- const [isDialogOpen, setIsDialogOpen] = useState(false);
- const { toast } = useToast();
- const db = usePGlite();
- const [entity] = useEntity();
-
- const handleErase = async () => {
- try {
- setIsErasing(true);
-
- await ERASE_OPFS_DB(db, entity?.id ?? 0);
-
- toast({
- title: "Database Erased Successfully",
- description: "All local data has been permanently deleted.",
- });
-
- setIsDialogOpen(false);
- } catch (error) {
- console.error("Failed to erase database:", error);
- toast({
- title: "Erase Failed",
- description: "Failed to erase the local database. Please try again.",
- variant: "destructive",
- });
- } finally {
- setIsErasing(false);
- }
- };
-
- return (
- <AlertDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
- <AlertDialogTrigger asChild>
- <Button
- variant="destructive"
- className={`gap-2 ${className}`}
- disabled={isErasing}
- >
- <Database className="h-4 w-4" />
- Erase Local Database
- </Button>
- </AlertDialogTrigger>
-
- <AlertDialogContent className="max-w-md">
- <AlertDialogHeader>
- <AlertDialogTitle className="flex items-center gap-2 text-destructive">
- <Trash2 className="h-5 w-5" />
- Erase Local Database
- </AlertDialogTitle>
- <AlertDialogDescription className="text-left space-y-2">
- <p className="font-medium text-foreground">
- This action cannot be undone.
- </p>
- <p>
- This will permanently delete all data stored in the Origin Private
- File System (OPFS) database on this device and trigger a re-sync,
- including:
- </p>
- <ul className="list-disc list-inside space-y-1 text-sm">
- <li>Transaction history</li>
- <li>Product catalog cache</li>
- <li>User preferences</li>
- <li>Offline data</li>
- </ul>
- <p className="text-sm text-muted-foreground">
- You will need to sync data from the server after erasing, which
- will take ~5 minutes.
- </p>
- </AlertDialogDescription>
- </AlertDialogHeader>
-
- <AlertDialogFooter>
- <AlertDialogCancel disabled={isErasing}>Cancel</AlertDialogCancel>
- <AlertDialogAction
- onClick={handleErase}
- disabled={isErasing}
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
- >
- {isErasing ? (
- <>
- <Loader2 className="h-4 w-4 animate-spin mr-2" />
- Erasing...
- </>
- ) : (
- <>
- <Trash2 className="h-4 w-4 mr-2" />
- Erase Database
- </>
- )}
- </AlertDialogAction>
- </AlertDialogFooter>
- </AlertDialogContent>
- </AlertDialog>
- );
-};
diff --git a/src/components/common/PurchaseOrderFinalizationDialog.tsx b/src/components/common/PurchaseOrderFinalizationDialog.tsx
index 7d12de80..273a0ba6 100644
--- a/src/components/common/PurchaseOrderFinalizationDialog.tsx
+++ b/src/components/common/PurchaseOrderFinalizationDialog.tsx
@@ -66,7 +66,6 @@ export const PurchaseOrderFinalizationDialog: React.FC<
if (open) {
form.reset(defaultValues);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, form]);
const onSubmit = async (data: FormData) => {
diff --git a/src/components/common/SalesHistoryCard/SalesHistoryCard.tsx b/src/components/common/SalesHistoryCard/SalesHistoryCard.tsx
index ad6c3537..6b165c73 100644
--- a/src/components/common/SalesHistoryCard/SalesHistoryCard.tsx
+++ b/src/components/common/SalesHistoryCard/SalesHistoryCard.tsx
@@ -532,7 +532,6 @@ const SaleHistoryVerticalTable = ({
captureException(error);
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
aggregateChildren,
endDate,
diff --git a/src/components/common/SavingIndicator/SavingIndicator.stories.tsx b/src/components/common/SavingIndicator/SavingIndicator.stories.tsx
index ee6d48c8..c72eaefc 100644
--- a/src/components/common/SavingIndicator/SavingIndicator.stories.tsx
+++ b/src/components/common/SavingIndicator/SavingIndicator.stories.tsx
@@ -1,4 +1,4 @@
-import { Meta, StoryObj } from "@storybook/react";
+import { Meta, StoryObj } from "@storybook/react/*";
import { SavingIndicator } from "./SavingIndicator";
const meta = {
diff --git a/src/components/feature-flags/useFeatureFlagEnabled.tsx b/src/components/feature-flags/useFeatureFlagEnabled.tsx
deleted file mode 100644
index 1d42e923..00000000
--- a/src/components/feature-flags/useFeatureFlagEnabled.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { captureException } from "config/sentry/TransformitySentry";
-import { usePostHog } from "posthog-js/react";
-import { useEffect, useState } from "react";
-import { BooleanParam, useQueryParam } from "use-query-params";
-
-export function useFeatureFlagEnabled(
- flag: string,
- defaultValue: boolean = false,
-): boolean {
- const client = usePostHog();
- const [query] = useQueryParam(flag, BooleanParam);
-
- const [featureEnabled, setFeatureEnabled] = useState<boolean | undefined>(
- () => {
- try {
- return client.isFeatureEnabled(flag);
- } catch (error) {
- captureException(error);
- return defaultValue;
- }
- },
- );
-
- useEffect(() => {
- return client.onFeatureFlags(() => {
- setFeatureEnabled((prev) => {
- try {
- client.isFeatureEnabled(flag);
- return client.isFeatureEnabled(flag);
- } catch (error) {
- captureException(error);
- return prev; // Return previous state if there's an error
- }
- });
- });
- }, [client, flag]);
-
- const val = query ?? featureEnabled ?? defaultValue;
- console.log(`Feature flag "${flag}" is ${val ? "enabled" : "disabled"}.`);
- return true;
-}
diff --git a/src/components/feature-flags/useOfflineModeDataSyncMigrationFlag.tsx b/src/components/feature-flags/useOfflineModeDataSyncMigrationFlag.tsx
deleted file mode 100644
index beedd549..00000000
--- a/src/components/feature-flags/useOfflineModeDataSyncMigrationFlag.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-import { useFeatureFlagEnabled } from "./useFeatureFlagEnabled";
-
-export const useOfflineModeDataSyncMigrationFlag = () =>
- useFeatureFlagEnabled("offline_mode_data_sync", false);
diff --git a/src/components/fulfillment/FulfillmentConfirmationModal.tsx b/src/components/fulfillment/FulfillmentConfirmationModal.tsx
deleted file mode 100644
index 4968bdb2..00000000
--- a/src/components/fulfillment/FulfillmentConfirmationModal.tsx
+++ /dev/null
@@ -1,226 +0,0 @@
-import { PermissionedButton } from "components/Auth/PermissionedButton";
-import { Badge } from "components/ui/badge";
-import { Button } from "components/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "components/ui/dialog";
-import { useToast } from "components/ui/use-toast";
-import { format } from "date-fns";
-import {
- CalendarDays,
- Clock,
- Loader2,
- MapPin,
- Package,
- Truck,
-} from "lucide-react";
-import {
- useGetFulfillment,
- usePatchFulfillmentId,
-} from "src/phoenix-generated";
-
-interface FulfillmentConfirmationModalProps {
- isOpen: boolean;
- onClose: () => void;
- fulfillmentId: string;
- onSuccess?: () => void;
-}
-
-const FulfillmentTypeIcon = {
- PICKUP: MapPin,
- SHIPPING: Truck,
- DEFAULT: Package,
-} as const;
-
-export const FulfillmentConfirmationModal: React.FC<
- FulfillmentConfirmationModalProps
-> = ({ isOpen, onClose, fulfillmentId, onSuccess }) => {
- const { toast } = useToast();
-
- const { data: fulfillment, isLoading: isFetchingFulfillment } =
- useGetFulfillment(fulfillmentId, {
- query: {
- enabled: isOpen && !!fulfillmentId,
- },
- });
-
- const { mutateAsync: updateFulfillment, isPending: isUpdating } =
- usePatchFulfillmentId({
- mutation: {
- onSuccess: () => {
- toast({
- title: "Success",
- description: "Order has been fulfilled successfully",
- variant: "success",
- });
- onSuccess?.();
- onClose();
- },
- onError: (error: any) => {
- toast({
- title: "Error",
- description:
- error?.response?.data?.message || "Failed to fulfill order",
- variant: "destructive",
- });
- },
- },
- });
-
- const handleConfirmFulfillment = async () => {
- await updateFulfillment({
- id: fulfillmentId,
- data: {
- status: "COMPLETED",
- },
- });
- };
-
- const TypeIcon = fulfillment?.type
- ? FulfillmentTypeIcon[
- fulfillment.type as keyof typeof FulfillmentTypeIcon
- ] || FulfillmentTypeIcon.DEFAULT
- : FulfillmentTypeIcon.DEFAULT;
-
- return (
- <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
- <DialogContent className="sm:max-w-[500px]">
- <DialogHeader>
- <DialogTitle className="flex items-center gap-2">
- <TypeIcon className="w-5 h-5" />
- Confirm Fulfillment
- </DialogTitle>
- <DialogDescription>
- Review the fulfillment details and confirm to complete the order.
- </DialogDescription>
- </DialogHeader>
-
- {isFetchingFulfillment ? (
- <div className="flex items-center justify-center py-8">
- <Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
- </div>
- ) : fulfillment ? (
- <div className="space-y-4">
- <div className="flex items-center justify-between">
- <span className="text-sm font-medium text-muted-foreground">
- Status
- </span>
- <Badge
- variant={
- fulfillment.status === "COMPLETED"
- ? "successful"
- : "secondary"
- }
- >
- {fulfillment.status}
- </Badge>
- </div>
-
- <div className="flex items-center justify-between">
- <span className="text-sm font-medium text-muted-foreground">
- Type
- </span>
- <Badge variant="outline" className="uppercase">
- {fulfillment.type}
- </Badge>
- </div>
-
- {fulfillment.metadata?.pickup && (
- <div className="rounded-lg border p-3 space-y-2 bg-muted/30">
- <div className="flex items-center gap-2 text-sm font-medium">
- <MapPin className="w-4 h-4" />
- Pickup Details
- </div>
- <div className="text-sm text-muted-foreground pl-6">
- Location: {fulfillment.metadata.pickup.pickup_location}
- </div>
- </div>
- )}
-
- {fulfillment.metadata?.shipping && (
- <div className="rounded-lg border p-3 space-y-2 bg-muted/30">
- <div className="flex items-center gap-2 text-sm font-medium">
- <Truck className="w-4 h-4" />
- Shipping Details
- </div>
- <div className="text-sm text-muted-foreground pl-6 space-y-1">
- <div>Carrier: {fulfillment.metadata.shipping.carrier}</div>
- <div>
- Tracking: {fulfillment.metadata.shipping.tracking_number}
- </div>
- </div>
- </div>
- )}
-
- <div className="grid grid-cols-2 gap-4 pt-2">
- <div className="flex items-center gap-2 text-sm text-muted-foreground">
- <CalendarDays className="w-4 h-4" />
- <div>
- <div className="font-medium">Created</div>
- <div>
- {format(
- new Date(fulfillment.createdAt),
- "MMM d, yyyy h:mm a",
- )}
- </div>
- </div>
- </div>
- <div className="flex items-center gap-2 text-sm text-muted-foreground">
- <Clock className="w-4 h-4" />
- <div>
- <div className="font-medium">Updated</div>
- <div>
- {format(
- new Date(fulfillment.updatedAt),
- "MMM d, yyyy h:mm a",
- )}
- </div>
- </div>
- </div>
- </div>
-
- {fulfillment.status === "COMPLETE" && (
- <div className="rounded-lg bg-green-50 border border-green-200 p-3 text-sm text-green-800">
- This order has already been fulfilled.
- </div>
- )}
- </div>
- ) : (
- <div className="py-8 text-center text-muted-foreground">
- Unable to load fulfillment details
- </div>
- )}
-
- <DialogFooter>
- <Button variant="outline" onClick={onClose} disabled={isUpdating}>
- Cancel
- </Button>
- <PermissionedButton
- requires="fulfillment/*:update"
- onClick={handleConfirmFulfillment}
- disabled={
- isUpdating ||
- isFetchingFulfillment ||
- !fulfillment ||
- ["COMPLETED", "CANCELED"].includes(fulfillment?.status ?? "")
- }
- >
- {isUpdating ? (
- <>
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
- Confirming...
- </>
- ) : (
- "Confirm Fulfillment"
- )}
- </PermissionedButton>
- </DialogFooter>
- </DialogContent>
- </Dialog>
- );
-};
diff --git a/src/components/label/LabelPrinterContext.tsx b/src/components/label/LabelPrinterContext.tsx
index 3140c9f1..b4ac7040 100644
--- a/src/components/label/LabelPrinterContext.tsx
+++ b/src/components/label/LabelPrinterContext.tsx
@@ -636,7 +636,6 @@ export const LabelPrintProvider = ({ children }: { children: ReactNode }) => {
await writeData(textToPrint);
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[SMALL_HEIGHT_LABEL, writeData],
);
diff --git a/src/components/loyalty/CustomerProfile/CustomerLoyaltyPointsTable.tsx b/src/components/loyalty/CustomerProfile/CustomerLoyaltyPointsTable.tsx
index b4ba2b91..7463217b 100644
--- a/src/components/loyalty/CustomerProfile/CustomerLoyaltyPointsTable.tsx
+++ b/src/components/loyalty/CustomerProfile/CustomerLoyaltyPointsTable.tsx
@@ -77,7 +77,6 @@ const CustomerLoyaltyPointsTable: React.FC<CustomerTransactionsTableProps> = ({
useEffect(() => {
onQueryKey(queryKeyRef);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryKey]);
return (
diff --git a/src/components/loyalty/CustomerProfile/CustomerTransactionsTable.tsx b/src/components/loyalty/CustomerProfile/CustomerTransactionsTable.tsx
index af9e5652..871a3dcc 100644
--- a/src/components/loyalty/CustomerProfile/CustomerTransactionsTable.tsx
+++ b/src/components/loyalty/CustomerProfile/CustomerTransactionsTable.tsx
@@ -49,7 +49,6 @@ export const CustomerTransactionsTable: React.FC<
useEffect(() => {
onQueryKey(queryKeyRef);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryKey]);
return (
diff --git a/src/components/loyalty/CustomerProfile/HouseAccount/HouseAccountDetailsView.tsx b/src/components/loyalty/CustomerProfile/HouseAccount/HouseAccountDetailsView.tsx
index 35968482..dfb4f517 100644
--- a/src/components/loyalty/CustomerProfile/HouseAccount/HouseAccountDetailsView.tsx
+++ b/src/components/loyalty/CustomerProfile/HouseAccount/HouseAccountDetailsView.tsx
@@ -370,13 +370,6 @@ export const PayHouseAmountFormWrapper: React.FC<
salesChannel={inStoreSalesChannel}
reviewTransactionModal={reviewTransactionModal}
payAfterConfirm={false}
- // Payment method functions (fallback implementations for house account context)
- paymentMethodTypeToPaymentMethod={{}}
- calculateMethodsWithPrices={() => []}
- findBestPaymentMethod={() => null}
- isCalculatingBackgroundPaymentMethodTotals={false}
- selectedSalesChannel={undefined}
- setSkipSetItemsInCart={() => undefined}
>
<PayHouseAmountForm
houseAccountId={houseAccountId}
diff --git a/src/components/navbar/NavBarPlain.tsx b/src/components/navbar/NavBarPlain.tsx
index 4c981880..97b6332c 100644
--- a/src/components/navbar/NavBarPlain.tsx
+++ b/src/components/navbar/NavBarPlain.tsx
@@ -5,7 +5,6 @@ import { Separator } from "components/ui/separator";
import { useEntity } from "context/EntityProvider";
import { Menu } from "lucide-react";
import React, { useState } from "react";
-import { useMediaQuery } from "usehooks-ts";
import { LockButton } from "../Auth/LockButton";
import { Breadcrumbs } from "../common/Breadcrumbs/Breadcrumbs";
import { ItemSearchShortcut } from "../common/ItemSearchShortcut";
@@ -45,8 +44,6 @@ export const NavBarPlain: React.FC<NavBarProps> = ({
const onOpen = () => setIsOpen(true);
const onClose = () => setIsOpen(false);
- const isMobile = useMediaQuery("(max-width: 768px)");
-
return (
<>
<div
@@ -57,25 +54,23 @@ export const NavBarPlain: React.FC<NavBarProps> = ({
)}
>
{/* Mobile */}
- {isMobile && (
- <div className="flex w-full items-center justify-between space-x-2">
- <div className="flex space-x-2">
- <Button
- variant="outline"
- size="sm"
- onClick={onOpen}
- className="p-2 md:p-3"
- aria-label="Open menu"
- >
- <Menu className="h-4 w-4" />
- </Button>
- {!!title && <h2 className="text-lg font-semibold">{title}</h2>}
- </div>
- <div>
- <CommandMenu showPlaceholder={false} />
- </div>
+ <div className="flex md:hidden w-full md:w-fit items-center justify-between space-x-2 md:space-x-3">
+ <div className="flex space-x-2">
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={onOpen}
+ className="p-2 md:p-3"
+ aria-label="Open menu"
+ >
+ <Menu className="h-4 w-4" />
+ </Button>
+ {!!title && <h2 className="text-lg font-semibold">{title}</h2>}
</div>
- )}
+ <div>
+ <CommandMenu showPlaceholder={false} />
+ </div>
+ </div>
<div className="hidden md:flex items-center space-x-2 md:space-x-3">
{!hideMenu && <MenuLinks />}
@@ -108,16 +103,14 @@ export const NavBarPlain: React.FC<NavBarProps> = ({
{/* Mobile Drawer */}
<MobileNavDrawer isOpen={isOpen} onClose={onClose} title={title}>
- {isOpen && (
- <MobileNavContent
- title={title}
- hideMenu={hideMenu}
- hideOverride={hideOverride}
- hidePopRegister={hidePopRegister}
- hideSearchShortcut={hideSearchShortcut}
- hideSalesScreenShortcut={hideSalesScreenShortcut}
- />
- )}
+ <MobileNavContent
+ title={title}
+ hideMenu={hideMenu}
+ hideOverride={hideOverride}
+ hidePopRegister={hidePopRegister}
+ hideSearchShortcut={hideSearchShortcut}
+ hideSalesScreenShortcut={hideSalesScreenShortcut}
+ />
</MobileNavDrawer>
</>
);
diff --git a/src/components/navbar/SaleScreenNavBar.tsx b/src/components/navbar/SaleScreenNavBar.tsx
index e2b30693..b66d43dc 100644
--- a/src/components/navbar/SaleScreenNavBar.tsx
+++ b/src/components/navbar/SaleScreenNavBar.tsx
@@ -19,7 +19,7 @@ import { StoreInfoWithSelect } from "./StoreInfoWithSelect";
import EnvironmentTag from "./environment/EnvironmentTag";
export type SaleScreenNavBarProps = {
- onSearchSelected?: (item?: EntityItemDetail) => void | Promise<void>;
+ onSearchSelected?: (item?: EntityItemDetail) => void;
};
const SaleScreenNavBar = forwardRef<ComboboxSelectRef, SaleScreenNavBarProps>(
diff --git a/src/components/paymentProcessor/FinixPaymentModal.tsx b/src/components/paymentProcessor/FinixPaymentModal.tsx
index 15d07def..88aee6c5 100644
--- a/src/components/paymentProcessor/FinixPaymentModal.tsx
+++ b/src/components/paymentProcessor/FinixPaymentModal.tsx
@@ -1,4 +1,3 @@
-import { CreditCardPriceOption } from "components/SalesScreenComponents/Modals/ManualCardPunchModal";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { TransactionPaymentForm } from "generated/types";
import { useEffect } from "react";
@@ -7,14 +6,11 @@ const finixEnv = import.meta.env.VITE_APP_FINIX_ENV;
export type FinixPaymentModalProps = {
onFormSubmit: () => void;
- priceSelected: CreditCardPriceOption;
};
-export const FinixPaymentModal = ({
- onFormSubmit,
- priceSelected,
-}: FinixPaymentModalProps) => {
- const { setAmountPaid, isPersisting } = useSalesPaymentContext();
+export const FinixPaymentModal = ({ onFormSubmit }: FinixPaymentModalProps) => {
+ const { transactionTotalPrice, setAmountPaid, isPersisting } =
+ useSalesPaymentContext();
const options = {
showAddress: true, // show address fields in the form (default is false)
@@ -53,8 +49,7 @@ export const FinixPaymentModal = ({
setAmountPaid({
amountPaid: 0,
- creditCardAmountReceived: priceSelected.total,
- paymentMethodId: priceSelected.method.id,
+ creditCardAmountReceived: transactionTotalPrice(),
paymentForm: TransactionPaymentForm["CREDIT CARD"],
creditCardId: token,
});
@@ -68,7 +63,6 @@ export const FinixPaymentModal = ({
showAddress: true,
onSubmit,
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <div id="form" />;
diff --git a/src/components/paymentProcessor/StripeCardPunchIn.tsx b/src/components/paymentProcessor/StripeCardPunchIn.tsx
index 089a918b..bbe43d86 100644
--- a/src/components/paymentProcessor/StripeCardPunchIn.tsx
+++ b/src/components/paymentProcessor/StripeCardPunchIn.tsx
@@ -5,23 +5,22 @@ import {
useStripe,
} from "@stripe/react-stripe-js";
import { Button } from "@tremor/react";
-import { CreditCardPriceOption } from "components/SalesScreenComponents/Modals/ManualCardPunchModal";
import { useSalesPaymentContext } from "context/Sales/SalesPaymentContext";
import { TransactionPaymentForm } from "generated/types";
import { useState } from "react";
export type CheckoutFormProps = {
onSubmit: () => void;
- priceSelected: CreditCardPriceOption;
};
-const CheckoutForm = ({ onSubmit, priceSelected }: CheckoutFormProps) => {
+const CheckoutForm = ({ onSubmit }: CheckoutFormProps) => {
const stripe = useStripe();
const elements = useElements();
const [errorMessage, setErrorMessage] = useState();
const [loading, setLoading] = useState(false);
- const { setAmountPaid, isPersisting } = useSalesPaymentContext();
+ const { transactionTotalPrice, setAmountPaid, isPersisting } =
+ useSalesPaymentContext();
const handleError = (error: any) => {
setLoading(false);
@@ -64,8 +63,7 @@ const CheckoutForm = ({ onSubmit, priceSelected }: CheckoutFormProps) => {
setAmountPaid({
amountPaid: 0,
- creditCardAmountReceived: priceSelected.total,
- paymentMethodId: priceSelected.method.id,
+ creditCardAmountReceived: transactionTotalPrice(),
paymentForm: TransactionPaymentForm["CREDIT CARD"],
creditCardId: paymentMethod?.id,
});
diff --git a/src/components/paymentProcessor/worldpay/WorldpayManualPaymentModal.tsx b/src/components/paymentProcessor/worldpay/WorldpayManualPaymentModal.tsx
index dfc14313..33e4eda9 100644
--- a/src/components/paymentProcessor/worldpay/WorldpayManualPaymentModal.tsx
+++ b/src/components/paymentProcessor/worldpay/WorldpayManualPaymentModal.tsx
@@ -1,4 +1,3 @@
-import { CreditCardPriceOption } from "components/SalesScreenComponents/Modals/ManualCardPunchModal";
import { useEntitySelected } from "context/EntityProvider";
import {
AmountReceived,
@@ -9,7 +8,6 @@ import { useScript } from "usehooks-ts";
export type WorldpayPaymentModalProps = {
onFormSubmit: () => void;
- priceSelected: CreditCardPriceOption;
};
interface CustomWindow extends Window {
@@ -23,9 +21,8 @@ declare let window: CustomWindow;
const WorldpayManualPaymentModal = ({
onFormSubmit,
- priceSelected,
}: WorldpayPaymentModalProps) => {
- const { setAmountPaid } = useSalesPaymentContext();
+ const { transactionTotalPrice, setAmountPaid } = useSalesPaymentContext();
const [entity] = useEntitySelected();
const scriptLoading = useScript(
@@ -60,10 +57,9 @@ const WorldpayManualPaymentModal = ({
console.log(response);
window.setPaymentSuccessRef({
amountPaid: 0,
- creditCardAmountReceived: ${priceSelected.total},
+ creditCardAmountReceived: ${transactionTotalPrice()},
paymentForm: "CREDIT CARD",
creditCardId: response.response.data.at(0).token,
- paymentMethodId: ${priceSelected.method.id},
});
}
PayFrame.onFinish = function (response) {
@@ -81,8 +77,7 @@ const WorldpayManualPaymentModal = ({
return () => {
document.body.removeChild(script);
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [entity.creditCardMerchantOnlineId, scriptLoading, priceSelected.total]); // Empty dependency array ensures this runs only once on mount
+ }, [entity.creditCardMerchantOnlineId, scriptLoading, transactionTotalPrice]); // Empty dependency array ensures this runs only once on mount
// Attach the setState function to the window
useEffect(() => {
diff --git a/src/components/payout/PayoutModal.tsx b/src/components/payout/PayoutModal.tsx
index 35185176..e8dffe1d 100644
--- a/src/components/payout/PayoutModal.tsx
+++ b/src/components/payout/PayoutModal.tsx
@@ -208,7 +208,6 @@ const PayoutModal = ({
onClose();
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[postPayout, reset, onClose],
);
diff --git a/src/components/pg-lite/PGliteProvider.tsx b/src/components/pg-lite/PGliteProvider.tsx
deleted file mode 100644
index 99361495..00000000
--- a/src/components/pg-lite/PGliteProvider.tsx
+++ /dev/null
@@ -1,537 +0,0 @@
-import { PGliteProvider as _PGliteProvider } from "@electric-sql/pglite-react";
-import type {
- MapColumnsFn,
- ShapeToTableOptions,
- SyncShapesToTablesResult,
-} from "@electric-sql/pglite-sync";
-import { PGliteWorker } from "@electric-sql/pglite/worker";
-import Loading from "components/Loading";
-import PGWorker from "components/pg-lite/pglite-worker.ts?worker";
-import { firebaseAuth } from "config/Firebase/firebase";
-import { useEntity } from "context/EntityProvider";
-import { useEffect, useRef, useState } from "react";
-import { typeidUnboxed } from "typeid-js";
-import { useLocalStorage } from "usehooks-ts";
-import {
- type CustomPGlite,
- ERASE_OPFS_DB,
- PG_LITE_INITIAL_SYNC_COMPLETE,
- PGLITE_OPTIONS,
-} from "./PgliteOptions";
-
-/**
- * Configuration for each table to be synced
- * name: The name of the table in the local PGlite database
- * primaryKey: The primary key columns for the table. This should match the primary key in the database as part of our abstraction.
- * Electric requires the primary key to match our shape data. Example: If the primary key is id in the DB and our prefix is ei, then the primary key is id. Our abstraction will make it ei_id.
- * columnPrefix: A prefix to add to each column name to avoid collisions
- * columns: Optional additional columns to include in the sync. These should match the column names in the database.
- * (on top of the columns returned by the shape)
- * e.g. for foreign keys or metadata
- */
-type TableConfig = {
- name: string;
- primaryKey: string[];
- columnPrefix: string;
- columns: string[]; // Optional additional columns to include
-};
-
-const PGliteProvider = ({ children }: { children: React.ReactNode }) => {
- const [client, setClient] = useState<CustomPGlite | undefined>(undefined);
-
- const subscriptionRef = useRef<SyncShapesToTablesResult>();
- const [entity] = useEntity();
-
- const [, setInitialSyncComplete] = useLocalStorage(
- PG_LITE_INITIAL_SYNC_COMPLETE(entity?.id ?? 0),
- false,
- );
-
- useEffect(() => {
- const currentUser = firebaseAuth.currentUser;
- const getIdToken = currentUser?.getIdToken;
- if (!getIdToken) {
- console.error("No user is currently authenticated.");
- return;
- }
- let worker: CustomPGlite | undefined;
- void PGliteWorker.create(
- new PGWorker({
- name: "pglite-worker",
- }),
- PGLITE_OPTIONS,
- ).then(async (pg) => {
- worker = pg;
-
- const tableConfigs: TableConfig[] = [
- {
- name: "transaction_item_cost_type",
- primaryKey: ["type"],
- columnPrefix: "tict",
- columns: ["type"],
- },
- {
- name: "cohort",
- primaryKey: ["id"],
- columnPrefix: "co",
- columns: ["id", "name", "created_at", "updated_at", "migration_id"],
- },
- {
- name: "cohort_item_size_unit",
- primaryKey: ["size_unit"],
- columnPrefix: "cits",
- columns: ["size_unit"],
- },
- {
- name: "department_group",
- primaryKey: ["id"],
- columnPrefix: "dg",
- columns: [
- "id",
- "cohort_id",
- "name",
- "created_at",
- "updated_at",
- "migration_id",
- ],
- },
- {
- name: "department",
- primaryKey: ["id"],
- columnPrefix: "dp",
- columns: [
- "name",
- "tax",
- "bottledeposit",
- "environmentfee",
- "updated_at",
- "id",
- "cohort_id",
- "has_revenue",
- "department_group_id",
- "migration_id",
- ],
- },
- {
- name: "item_type",
- primaryKey: ["id"],
- columnPrefix: "it",
- columns: ["id", "type"],
- },
- {
- name: "cohort_item",
- primaryKey: ["id"],
- columnPrefix: "ci",
- columns: [
- "id",
- "cohort_id",
- "name",
- "case_quantity",
- "size",
- "size_unit",
- "alcohol_by_volume",
- "deposit_multiplier",
- "environment_fee_multiplier",
- "parent_cohort_item_id",
- "parent_quantity",
- "notes",
- "changed_by",
- "created_at",
- "updated_at",
- "migration_id",
- "parent_migration_id",
- "department",
- "brand",
- "pack_size",
- "alcoholic",
- "vintage",
- "item_type_id",
- "version",
- ],
- },
- {
- name: "cohort_vendor",
- primaryKey: ["id"],
- columnPrefix: "cv",
- columns: [
- "id",
- "cohort_id",
- "vendor_id",
- "vendor_name",
- "created_at",
- "updated_at",
- "changed_by",
- "email",
- "phone_number",
- "migration_id",
- "is_exclusive",
- ],
- },
- {
- name: "entity_minimum_price_source_type",
- primaryKey: ["type"],
- columnPrefix: "empst",
- columns: ["type"],
- },
- {
- name: "cohort_item_vintage",
- primaryKey: ["id"],
- columnPrefix: "civ",
- columns: [
- "id",
- "cohort_item_id",
- "vintage",
- "rating",
- "reviewer",
- "note",
- "created_at",
- "updated_at",
- "version",
- "reviewer_code",
- "cohort_id",
- ],
- },
- {
- name: "address",
- primaryKey: ["id"],
- columnPrefix: "adr",
- columns: [
- "id",
- "line1",
- "line2",
- "city",
- "state",
- "country",
- "postal_code",
- "created_at",
- "updated_at",
- ],
- },
- {
- name: "entity",
- primaryKey: ["id"],
- columnPrefix: "ey",
- columns: [
- "name",
- "id",
- "credit_card_merchant_application_id",
- "credit_card_merchant_id",
- "address",
- "fintech_host",
- "fintech_user",
- "fintech_passwd",
- "fintech_path",
- "payment_processor",
- "payment_fee_fixed",
- "payment_fee_percent",
- "updated_at",
- "phone_number",
- "cohort_id",
- "location_id",
- "timezone",
- "created_at",
- "card_not_present_payment_fee_fixed",
- "card_not_present_payment_fee_percent",
- "surcharge_fee",
- "credit_card_merchant_token",
- "credit_card_terminal_id",
- "credit_card_merchant_online_id",
- "short_name",
- "transaction_item_cost_type",
- "email",
- "address_id",
- "minimum_price_source_type",
- ],
- },
- {
- name: "entity_item",
- primaryKey: ["id"],
- columnPrefix: "ei",
- columns: [
- "id",
- "entity_id",
- "cohort_item_id",
- "price",
- "minimum_price",
- "cost",
- "discount_allowed",
- "quantity",
- "aisle_location",
- "fridge_location",
- "last_quantity_received",
- "changed_by",
- "created_at",
- "updated_at",
- "migration_id",
- "last_order_date",
- "exclusive",
- "case_cost",
- "variable_cost_percent",
- "last_cohort_vendor_id",
- "preferred_cohort_vendor_id",
- "average_cost",
- "sellable",
- "version",
- "cohort_item_vintage_id",
- "true_cost",
- ],
- },
- {
- name: "entity_tag",
- primaryKey: ["id"],
- columnPrefix: "et",
- columns: ["id", "name", "updated_at", "cohort_id", "migration_id"],
- },
- {
- name: "entity_attribute",
- primaryKey: ["id"],
- columnPrefix: "eattr",
- columns: ["id", "description"],
- },
- {
- name: "entity_configuration",
- primaryKey: ["entity_id", "attribute_id"],
- columnPrefix: "ecfg",
- columns: ["entity_id", "attribute_id", "value"],
- },
- {
- name: "register",
- primaryKey: ["entity_id", "register_number"],
- columnPrefix: "reg",
- columns: [
- "entity_id",
- "register_number",
- "credit_card_device_id",
- "updated_at",
- ],
- },
- {
- name: "bill_denomination",
- primaryKey: ["denomination_dollar_value"],
- columnPrefix: "bd",
- columns: ["denomination_dollar_value", "denomination_type"],
- },
- {
- name: "sales_channel_type",
- primaryKey: ["id"],
- columnPrefix: "sct",
- columns: ["id", "name", "description", "created_at", "config"],
- },
- {
- name: "cohort_price_level",
- primaryKey: ["id"],
- columnPrefix: "cpl",
- columns: [
- "id",
- "cohort_id",
- "name",
- "markup_percent",
- "markup_cohort_price_level_id",
- "migration_id",
- ],
- },
- {
- name: "entity_sales_channel",
- primaryKey: ["id"],
- columnPrefix: "esc",
- columns: [
- "id",
- "sales_channel_type_id",
- "entity_id",
- "created_at",
- "updated_at",
- "account_id",
- "active",
- "external_location_id",
- "name",
- "taxable",
- "price_level_id",
- "external_integration_enabled",
- "external_integration_attempt",
- "external_address_line_1",
- "external_address_line_2",
- "external_address_city",
- "external_address_state",
- "external_address_zip",
- "external_requestor_name",
- "external_requestor_email",
- "external_merchant_decision_maker_email",
- "sftp_credentials",
- "configuration",
- "auto_add_new_departments",
- "allow_negative_inventory",
- ],
- },
- {
- name: "cohort_item_tag",
- primaryKey: ["id"],
- columnPrefix: "cit",
- columns: [
- "id",
- "cohort_item_id",
- "tag_id",
- "updated_at",
- "created_at",
- "changed_by",
- "cohort_id",
- ],
- },
- {
- name: "cohort_item_barcode",
- primaryKey: ["cohort_item_id", "barcode"],
- columnPrefix: "cib",
- columns: ["cohort_item_id", "barcode", "created_at", "cohort_id"],
- },
- {
- name: "cohort_item_vendor_item",
- primaryKey: ["cohort_item_id", "cohort_vendor_id"],
- columnPrefix: "civi",
- columns: [
- "cohort_item_id",
- "vendor",
- "sku",
- "updated_at",
- "created_at",
- "changed_by",
- "cohort_vendor_id",
- "cohort_id",
- ],
- },
- {
- name: "entity_sales_channel_item",
- primaryKey: ["id"],
- columnPrefix: "esci",
- columns: [
- "id",
- "entity_sales_channel_id",
- "entity_item_id",
- "active",
- "created_at",
- "updated_at",
- "external_item_id",
- "entity_id",
- ],
- },
- {
- name: "casbin_rule_role",
- primaryKey: ["id"],
- columnPrefix: "crr",
- columns: ["id", "ptype", "v0", "v1", "v2", "v3", "v4", "v5"],
- },
- {
- name: "casbin_rule_user",
- primaryKey: ["id"],
- columnPrefix: "cru",
- columns: ["id", "ptype", "v0", "v1", "v2", "v3", "v4", "v5"],
- },
- // { name: "drawer_settlement", primaryKey: ["id"] },
- // { name: "transactionclosings", primaryKey: ["id"] },
- // Add more table configurations here as needed
- ];
-
- const shapes: Record<string, ShapeToTableOptions> = {};
-
- const electricUrl = import.meta.env.VITE_APP_ZEUS_URL;
-
- tableConfigs.forEach((config) => {
- const defaultMapColumnsPrefixed = (
- message: Parameters<MapColumnsFn>[0],
- prefix?: string,
- ) => {
- if (prefix) {
- return Object.fromEntries(
- Object.entries(message.value).map(([key, value]) => [
- `${prefix}_${key}`,
- value,
- ]),
- );
- }
- return { ...message.value };
- };
-
- const defaultMapColumns: MapColumnsFn = (message) => {
- return defaultMapColumnsPrefixed(message, config.columnPrefix);
- };
-
- shapes[config.name] = {
- shape: {
- url: `${electricUrl}/v1/shape`,
- headers: {
- // Token will be refreshed on each request
- Authorization: async () =>
- `Bearer ${await firebaseAuth.currentUser?.getIdToken()}`,
- "X-Request-Id": () => typeidUnboxed<"req">("req"),
- },
- params: {
- table: config.name,
- replica: "full",
- columns: config.columns,
- entityId: entity?.id.toString(),
- },
- },
- table: config.name,
- mapColumns: defaultMapColumns,
- // Electric requires the primary key to match our shape data. Example: If the primary key is id in the DB and our prefix is ei, then the primary key is id. Our abstraction will make it ei_id.
- primaryKey: config.primaryKey.map((col) => {
- if (config.columnPrefix) {
- return `${config.columnPrefix}_${col}`;
- }
- return col;
- }),
- onMustRefetch: async (tx) => {
- console.log(`Refetching shape for table: ${config.name}`);
- try {
- await tx.exec(`
- SET session_replication_role = 'replica';
- `);
- await tx.exec(`TRUNCATE TABLE "${config.name}" CASCADE;`);
- } catch (error) {
- console.error(`Error clearing table ${config.name}:`, error);
- await ERASE_OPFS_DB(pg, entity?.id ?? 0);
- }
- },
- };
- });
-
- const sub = await pg.electric.syncShapesToTables({
- shapes: shapes,
- key: `non-null`, // https://pglite.dev/docs/sync#syncshapestotables-api
- initialInsertMethod: "csv",
- onInitialSync: async () => {
- console.log("Initial sync complete");
- setInitialSyncComplete(true);
- await pg.exec(`SET session_replication_role = 'origin';`);
- },
- });
-
- subscriptionRef.current = sub;
-
- setClient(pg);
- });
-
- return () => {
- console.log("Cleaning up PGlite worker");
- if (subscriptionRef.current) {
- console.log("Unsubscribing from PGlite sync");
- subscriptionRef.current.unsubscribe();
- }
- if (worker) {
- void worker.close().then(() => {
- console.log("PGlite worker closed");
- });
- }
- };
- }, [entity?.id, setInitialSyncComplete]);
-
- if (!client) {
- return <Loading />;
- }
-
- return <_PGliteProvider db={client}>{children}</_PGliteProvider>;
-};
-
-const PGlineRolloutProvider = ({ children }: { children: React.ReactNode }) => {
- return <PGliteProvider>{children}</PGliteProvider>;
-};
-
-export default PGlineRolloutProvider;
diff --git a/src/components/pg-lite/PGliteSyncContext.tsx b/src/components/pg-lite/PGliteSyncContext.tsx
deleted file mode 100644
index cd84fe63..00000000
--- a/src/components/pg-lite/PGliteSyncContext.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { useEntity } from "context/EntityProvider";
-import { useLocalStorage } from "usehooks-ts";
-import { PG_LITE_INITIAL_SYNC_COMPLETE } from "./PgliteOptions";
-
-export const usePGliteSync = () => {
- const [entity] = useEntity();
- const [initialSyncComplete] = useLocalStorage(
- PG_LITE_INITIAL_SYNC_COMPLETE(entity?.id ?? 0),
- false,
- );
-
- console.log("initialSyncComplete =", initialSyncComplete);
-
- return {
- isSyncing: !initialSyncComplete,
- };
-};
diff --git a/src/components/pg-lite/PgliteOptions.ts b/src/components/pg-lite/PgliteOptions.ts
deleted file mode 100644
index c99cc879..00000000
--- a/src/components/pg-lite/PgliteOptions.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {
- type DebugLevel,
- IdbFs,
- type PGliteInterface,
- type PGliteInterfaceExtensions,
-} from "@electric-sql/pglite";
-import { electricSync } from "@electric-sql/pglite-sync";
-import { live } from "@electric-sql/pglite/live";
-import { vector } from "@electric-sql/pglite/vector";
-import type { PGliteWorker } from "@electric-sql/pglite/worker";
-
-export const PG_LITE_INITIAL_SYNC_COMPLETE = (entityId: number) =>
- `${entityId}-pg-lite-initial-sync-complete`;
-
-export type CustomPGlite = PGliteWorker &
- PGliteInterfaceExtensions<{
- live: typeof live;
- vector: typeof vector;
- electric: ReturnType<typeof electricSync>;
- }>;
-
-// https://github.com/electric-sql/pglite/blob/cab4ce64135a147f284ef5fa448ddcf17d22d666/packages/pglite/src/fs/opfs-ahp.ts
-// const opfsAhpFs = new OpfsAhpFS("pglite-db", {
-// // debug: true,
-// });
-
-const indexedDbFS = new IdbFs("pglite-db");
-
-export const ERASE_OPFS_DB = async (db: PGliteInterface, entityId: number) => {
- await db.close();
- const databases = await indexedDB.databases();
- for (const db of databases) {
- if (db.name?.includes("pglite")) {
- indexedDB.deleteDatabase(db.name);
- }
- }
-
- const opfs = await navigator.storage.getDirectory();
- if ("remove" in opfs) {
- // @ts-expect-error remove is not yet in the type definition and not standardized. https://developer.mozilla.org/en-US/docs/Web/API/FileSystemHandle/remove
- await opfs.remove({ recursive: true });
- }
- localStorage.removeItem(PG_LITE_INITIAL_SYNC_COMPLETE(entityId));
- window.location.reload();
-};
-
-// Decent reference at https://github.com/ToramCalculator-Team/ToramCalculator/blob/4bf557c219eb870746efa5c210d572885ddd7133/src/worker/PGlite.worker.ts#L100
-export const PGLITE_OPTIONS = {
- relaxedDurability: true,
- fs: indexedDbFS,
- debug: 5 as DebugLevel,
- extensions: {
- live,
- vector,
- electric: electricSync({
- debug: true,
- }),
- },
-};
diff --git a/src/components/pg-lite/migration.ts b/src/components/pg-lite/migration.ts
deleted file mode 100644
index 089ae2cd..00000000
--- a/src/components/pg-lite/migration.ts
+++ /dev/null
@@ -1,760 +0,0 @@
-type Migration = {
- id: string;
- script: string;
-};
-const TRANSACTION_ITEM_COST_TYPE_MIGRATION = `
- DROP TABLE IF EXISTS transaction_item_cost_type CASCADE;
- CREATE TABLE IF NOT EXISTS transaction_item_cost_type
- (
- tict_type varchar(255) not null
- primary key
- );`;
-
-const COHORT_MIGRATION = `
- DROP TABLE IF EXISTS cohort CASCADE;
- CREATE TABLE IF NOT EXISTS cohort
- (
- co_id bigint
- primary key,
- co_name text not null,
- co_created_at timestamp with time zone default CURRENT_TIMESTAMP,
- co_updated_at timestamp with time zone default CURRENT_TIMESTAMP,
- co_migration_id text
- unique
- );`;
-
-const COHORT_ITEM_SIZE_UNIT_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item_size_unit CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item_size_unit
- (
- cits_size_unit varchar(255) not null
- constraint cohort_item_size_unit_pk
- primary key
- );`;
-
-const DEPARTMENT_GROUP_MIGRATION = `
- DROP TABLE IF EXISTS department_group CASCADE;
- CREATE TABLE IF NOT EXISTS department_group
- (
- dg_id bigint
- primary key,
- dg_cohort_id bigint not null
- references cohort,
- dg_name varchar(255) not null,
- dg_created_at timestamp default now() not null,
- dg_updated_at timestamp default now() not null,
- dg_migration_id text,
- constraint department_group_unique_name
- unique (dg_cohort_id, dg_name),
- constraint department_group_migration_id_key
- unique (dg_cohort_id, dg_migration_id)
- );`;
-
-const DEPARTMENT_MIGRATION = `
- DROP TABLE IF EXISTS department CASCADE;
- CREATE TABLE IF NOT EXISTS department
- (
- dp_name varchar(255) not null,
- dp_tax numeric(38, 6) not null
- constraint department_tax_no_nan
- check (dp_tax <> 'NaN'::numeric),
- dp_bottledeposit numeric(38, 2) not null
- constraint department_bottledeposit_no_nan
- check (dp_bottledeposit <> 'NaN'::numeric),
- dp_environmentfee numeric(38, 2) not null
- constraint department_environmentfee_no_nan
- check (dp_environmentfee <> 'NaN'::numeric),
- dp_updated_at timestamp with time zone default now() not null,
- dp_id bigint
- primary key,
- dp_cohort_id bigint
- references cohort
- on delete cascade,
- dp_has_revenue boolean default true not null,
- dp_department_group_id bigint not null
- references department_group,
- dp_migration_id text,
- constraint department_pk
- unique (dp_cohort_id, dp_name),
- constraint department_migration_id_key
- unique (dp_cohort_id, dp_migration_id),
- constraint gift_cert_no_tax
- check (((dp_name)::text <> 'Gift Cert'::text) OR
- ((dp_tax = (0)::numeric) AND (dp_bottledeposit = (0)::numeric) AND (dp_environmentfee = (0)::numeric)))
- );`;
-
-const ITEM_TYPE_MIGRATION = `
- DROP TABLE IF EXISTS item_type CASCADE;
- CREATE TABLE IF NOT EXISTS item_type
- (
- it_id bigint
- primary key,
- it_type text not null
- unique
- );`;
-
-const COHORT_ITEM_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item (
- ci_id bigint CONSTRAINT cohort_item_pk PRIMARY KEY,
- ci_cohort_id bigint NOT NULL CONSTRAINT cohort_item_cohort_id_fk REFERENCES cohort ON UPDATE CASCADE ON DELETE RESTRICT,
- ci_name varchar(255) NOT NULL,
- ci_case_quantity integer DEFAULT 1 NOT NULL CONSTRAINT positive_case_quantity CHECK ((ci_case_quantity IS NULL) OR (ci_case_quantity >= 1)),
- ci_size numeric(10, 4) CONSTRAINT cohort_item_size_no_nan CHECK (ci_size <> 'NaN'::numeric),
- ci_size_unit varchar(255) CONSTRAINT cohort_item_cohort_item_size_unit_size_unit_fk REFERENCES cohort_item_size_unit,
- ci_alcohol_by_volume varchar(255),
- ci_deposit_multiplier integer NOT NULL,
- ci_environment_fee_multiplier integer NOT NULL,
- ci_parent_cohort_item_id bigint,
- ci_parent_quantity NUMERIC(12, 6),
- ci_notes text,
- ci_changed_by varchar(255),
- ci_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ci_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ci_migration_id varchar(255),
- ci_parent_migration_id varchar(255),
- ci_department bigint NOT NULL CONSTRAINT cohort_item_department_id_fk REFERENCES department ON UPDATE CASCADE,
- ci_brand varchar(255),
- ci_pack_size integer CONSTRAINT positive_pack_size CHECK ((ci_pack_size IS NULL) OR (ci_pack_size >= 0)),
- ci_alcoholic boolean DEFAULT TRUE NOT NULL,
- ci_vintage varchar(255),
- ci_item_type_id bigint NOT NULL REFERENCES item_type,
- ci_version bigint DEFAULT 1 NOT NULL,
- CONSTRAINT cohort_item_pk_2 UNIQUE (ci_cohort_id, ci_migration_id),
- CONSTRAINT valid_parent_item CHECK ((ci_parent_cohort_item_id IS NULL) OR ((ci_parent_cohort_item_id IS NOT NULL) AND (ci_parent_quantity IS NOT NULL) AND (ci_parent_quantity > 0))),
- CONSTRAINT valid_size CHECK ((ci_size IS NULL) OR ((ci_size IS NOT NULL) AND (ci_size_unit IS NOT NULL)))
- );`;
-
-const COHORT_VENDOR_MIGRATION = `
- DROP TABLE IF EXISTS cohort_vendor CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_vendor (
- cv_id bigint CONSTRAINT cohort_vendor_pk PRIMARY KEY,
- cv_cohort_id bigint NOT NULL CONSTRAINT cohort_vendor_cohort_id_fk REFERENCES cohort ON UPDATE CASCADE ON DELETE RESTRICT,
- cv_vendor_id text NOT NULL,
- cv_vendor_name text NOT NULL,
- cv_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- cv_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- cv_changed_by text,
- cv_email text,
- cv_phone_number text,
- cv_migration_id text,
- cv_is_exclusive boolean DEFAULT FALSE NOT NULL,
- CONSTRAINT cohort_vendor_pk_2 UNIQUE (cv_cohort_id, cv_migration_id)
- );`;
-
-const COHORT_ITEM_VINTAGE_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item_vintage CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item_vintage (
- civ_id varchar(255) NOT NULL CONSTRAINT cohort_item_vintage_pk PRIMARY KEY,
- civ_cohort_item_id bigint NOT NULL CONSTRAINT cohort_item_vintage_cohort_item_id_fk REFERENCES cohort_item ON UPDATE CASCADE ON DELETE CASCADE,
- civ_vintage text NOT NULL,
- civ_rating text,
- civ_reviewer text,
- civ_note text,
- civ_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- civ_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- civ_version bigint DEFAULT 1 NOT NULL,
- civ_reviewer_code text,
- civ_cohort_id bigint CONSTRAINT cohort_item_vintage_cohort_id_fk REFERENCES cohort,
- CONSTRAINT cohort_item_vintage_pk_2 UNIQUE (civ_cohort_item_id, civ_vintage)
- );`;
-
-const ADDRESS_MIGRATION = `
- DROP TABLE IF EXISTS address CASCADE;
- CREATE TABLE address
- (
- adr_id varchar(255) not null
- primary key,
- adr_line1 text not null,
- adr_line2 text,
- adr_city text not null,
- adr_state text not null,
- adr_country text not null,
- adr_postal_code text not null,
- adr_created_at timestamp with time zone default now() not null,
- adr_updated_at timestamp with time zone default now() not null
- );`;
-
-const ENTITY_MIGRATION = `
- DROP TABLE IF EXISTS entity CASCADE;
-
-
- CREATE TABLE IF NOT EXISTS entity (
- ey_name varchar(255),
- ey_id bigint NOT NULL CONSTRAINT entity_pk PRIMARY KEY,
- ey_credit_card_merchant_application_id varchar(255),
- ey_credit_card_merchant_id varchar(255),
- ey_address varchar(255) NOT NULL,
- ey_fintech_host varchar(255),
- ey_fintech_user varchar(255),
- ey_fintech_passwd varchar(255),
- ey_fintech_path varchar(255),
- ey_payment_processor text,
- ey_payment_fee_fixed numeric(8, 4) DEFAULT 0.10 NOT NULL CONSTRAINT entity_payment_fee_fixed_no_nan CHECK (ey_payment_fee_fixed <> 'NaN'::numeric),
- ey_payment_fee_percent numeric(7, 4) DEFAULT 1.80 NOT NULL CONSTRAINT entity_payment_fee_percent_no_nan CHECK (ey_payment_fee_percent <> 'NaN'::numeric),
- ey_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ey_phone_number text,
- ey_cohort_id bigint NOT NULL CONSTRAINT entity_cohort_id_fk REFERENCES cohort ON UPDATE CASCADE,
- ey_location_id text,
- ey_timezone text DEFAULT 'America/New_York'::text NOT NULL,
- ey_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ey_card_not_present_payment_fee_fixed numeric(10, 4) NOT NULL CONSTRAINT entity_card_not_present_payment_fee_fixed_no_nan CHECK (ey_card_not_present_payment_fee_fixed <> 'NaN'::numeric),
- ey_card_not_present_payment_fee_percent numeric(10, 4) NOT NULL CONSTRAINT entity_card_not_present_payment_fee_percent_no_nan CHECK (ey_card_not_present_payment_fee_percent <> 'NaN'::numeric),
- ey_surcharge_fee boolean NOT NULL,
- ey_credit_card_merchant_token text,
- ey_credit_card_terminal_id text,
- ey_credit_card_merchant_online_id text,
- ey_short_name text,
- ey_transaction_item_cost_type varchar(255) NOT NULL REFERENCES transaction_item_cost_type,
- ey_email text,
- ey_address_id varchar(255)
- constraint entity_address_id_fk
- references address
- on update cascade on delete restrict,
- CONSTRAINT credit_card_processor_stripe CHECK ((ey_payment_processor IS NULL) OR (ey_payment_processor <> 'stripe'::text) OR ((ey_credit_card_merchant_application_id IS NOT NULL) AND (ey_credit_card_merchant_id IS NOT NULL) AND (ey_payment_fee_fixed IS NOT NULL) AND (ey_payment_fee_percent IS NOT NULL))),
- CONSTRAINT fintech_onboarded CHECK ((ey_fintech_host IS NULL) OR ((ey_fintech_host IS NOT NULL) AND (ey_fintech_passwd IS NOT NULL) AND (ey_fintech_user IS NOT NULL) AND (ey_fintech_path IS NOT NULL)))
- );
-
- ALTER TABLE entity
- ADD COLUMN IF NOT EXISTS ey_minimum_price_source_type VARCHAR(255)
- REFERENCES entity_minimum_price_source_type(empst_type);
-`;
-
-const ENTITY_ITEM_MIGRATION = `
- DROP TABLE IF EXISTS entity_item CASCADE;
- CREATE TABLE IF NOT EXISTS entity_item (
- ei_id bigint PRIMARY KEY,
- ei_entity_id bigint NOT NULL,
- ei_cohort_item_id bigint NOT NULL CONSTRAINT entity_item_cohort_item_id_fk REFERENCES cohort_item ON UPDATE CASCADE ON DELETE CASCADE,
- ei_price numeric(10, 2) NOT NULL CONSTRAINT entity_item_price_no_nan CHECK (ei_price <> 'NaN'::numeric),
- ei_minimum_price numeric(10, 2) CONSTRAINT entity_item_minimum_price_no_nan CHECK (ei_minimum_price <> 'NaN'::numeric),
- ei_cost NUMERIC(10, 2) CONSTRAINT entity_item_cost_no_nan CHECK (ei_cost <> 'NaN'::numeric),
- ei_discount_allowed boolean DEFAULT TRUE NOT NULL,
- ei_quantity numeric(10, 4) DEFAULT 0 NOT NULL CONSTRAINT entity_item_quantity_no_nan CHECK (ei_quantity <> 'NaN'::numeric),
- ei_aisle_location text,
- ei_fridge_location text,
- ei_last_quantity_received integer,
- ei_changed_by varchar(255),
- ei_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ei_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- ei_migration_id varchar(255),
- ei_last_order_date timestamp with time zone,
- ei_exclusive boolean NOT NULL,
- ei_case_cost numeric(10, 2) CONSTRAINT entity_item_case_cost_no_nan CHECK (ei_case_cost <> 'NaN'::numeric),
- ei_variable_cost_percent numeric(10, 2) CONSTRAINT entity_item_variable_cost_percent_no_nan CHECK (ei_variable_cost_percent <> 'NaN'::numeric),
- ei_last_cohort_vendor_id bigint CONSTRAINT entity_item_cohort_vendor_id_fk REFERENCES cohort_vendor ON UPDATE CASCADE,
- ei_preferred_cohort_vendor_id bigint CONSTRAINT entity_item_cohort_vendor_id_fk_2 REFERENCES cohort_vendor ON UPDATE CASCADE,
- ei_average_cost numeric(10, 4) CONSTRAINT entity_item_average_cost_no_nan CHECK (ei_average_cost <> 'NaN'::numeric),
- ei_sellable boolean NOT NULL,
- ei_version bigint DEFAULT 1 NOT NULL,
- ei_cohort_item_vintage_id varchar(255) CONSTRAINT entity_item_cohort_item_vintage_id_fk REFERENCES cohort_item_vintage ON UPDATE CASCADE,
- ei_true_cost numeric(10, 2),
- CONSTRAINT entity_item_pk2 UNIQUE (ei_entity_id, ei_migration_id),
- CONSTRAINT entity_item_pk3 UNIQUE (ei_entity_id, ei_cohort_item_id)
- );
-
- CREATE INDEX IF NOT EXISTS entity_item_cohort_item_id_index ON entity_item (ei_cohort_item_id);
-
- CREATE INDEX IF NOT EXISTS entity_item_vintage_index ON entity_item (ei_cohort_item_vintage_id);
-
- ALTER TABLE entity_item
- DROP CONSTRAINT IF EXISTS entity_item_entity_id_fk;
-
- ALTER TABLE entity_item
- ADD CONSTRAINT entity_item_entity_id_fk FOREIGN KEY (ei_entity_id) REFERENCES entity;`;
-
-const ENTITY_TAG_MIGRATION = `
- DROP TABLE IF EXISTS entity_tag CASCADE;
- CREATE TABLE IF NOT EXISTS entity_tag (
- et_id serial PRIMARY KEY,
- et_name text NOT NULL,
- et_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- et_cohort_id bigint NOT NULL CONSTRAINT entity_tag_cohort_id_fk REFERENCES cohort ON UPDATE CASCADE ON DELETE CASCADE,
- et_migration_id text,
- CONSTRAINT entity_tag_pk2 UNIQUE (et_cohort_id, et_name),
- CONSTRAINT entity_tag_migration_id_key UNIQUE (et_cohort_id, et_migration_id)
- );`;
-
-const ENTITY_ATTRIBUTE_MIGRATION = `
- DROP TABLE IF EXISTS entity_attribute CASCADE;
- CREATE TABLE IF NOT EXISTS entity_attribute (
- eattr_id text NOT NULL CONSTRAINT entity_attribute_pk PRIMARY KEY CONSTRAINT check_name CHECK (eattr_id = UPPER(eattr_id)),
- eattr_description text
- );`;
-
-const ENTITY_CONFIGURATION_MIGRATION = `
- DROP TABLE IF EXISTS entity_configuration CASCADE;
- CREATE TABLE IF NOT EXISTS entity_configuration (
- ecfg_entity_id bigint NOT NULL CONSTRAINT entity_configuration_entity_id_fk REFERENCES entity ON UPDATE CASCADE ON DELETE CASCADE,
- ecfg_attribute_id text NOT NULL CONSTRAINT entity_configuration_entity_attribute_id_fk REFERENCES entity_attribute ON UPDATE CASCADE ON DELETE CASCADE,
- ecfg_value text NOT NULL,
- CONSTRAINT entity_configuration_pk PRIMARY KEY (ecfg_entity_id, ecfg_attribute_id)
- );`;
-
-const REGISTER_MIGRATION = `
- DROP TABLE IF EXISTS register CASCADE;
- CREATE TABLE IF NOT EXISTS register (
- reg_entity_id bigint NOT NULL CONSTRAINT register_entity_id_fk REFERENCES entity ON UPDATE CASCADE ON DELETE CASCADE,
- reg_register_number bigint NOT NULL,
- reg_credit_card_device_id varchar(255),
- reg_updated_at timestamp with time zone DEFAULT NOW(),
- PRIMARY KEY (reg_entity_id, reg_register_number)
- );`;
-
-const BILL_DENOMINATION_MIGRATION = `
- DROP TABLE IF EXISTS bill_denomination CASCADE;
- CREATE TABLE IF NOT EXISTS bill_denomination (
- bd_denomination_dollar_value numeric(10, 4) NOT NULL PRIMARY KEY CONSTRAINT bill_denomination_denomination_dollar_value_no_nan CHECK (bd_denomination_dollar_value <> 'NaN'::numeric),
- bd_denomination_type text NOT NULL
- );`;
-
-const SALES_CHANNEL_TYPE_MIGRATION = `
- DROP TABLE IF EXISTS sales_channel_type CASCADE;
- CREATE TABLE IF NOT EXISTS sales_channel_type (
- sct_id bigint PRIMARY KEY,
- sct_name varchar(255) NOT NULL CONSTRAINT sales_channel_type_name_unique UNIQUE,
- sct_description text,
- sct_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- sct_config jsonb
- );`;
-
-const COHORT_PRICE_LEVEL_MIGRATION = `
- DROP TABLE IF EXISTS cohort_price_level CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_price_level (
- cpl_id bigint PRIMARY KEY,
- cpl_cohort_id bigint NOT NULL REFERENCES cohort ON DELETE CASCADE,
- cpl_name text NOT NULL,
- cpl_markup_percent numeric(10, 4) NOT NULL CONSTRAINT cohort_price_level_markup_percent_no_nan CHECK (cpl_markup_percent <> 'NaN'::numeric),
- cpl_markup_cohort_price_level_id bigint REFERENCES cohort_price_level ON UPDATE CASCADE ON DELETE RESTRICT,
- cpl_migration_id text,
- CONSTRAINT unique_cohort_price_level_name UNIQUE (cpl_cohort_id, cpl_name),
- CONSTRAINT cohort_price_level_migration_id_key UNIQUE (cpl_cohort_id, cpl_migration_id)
- );`;
-
-const ENTITY_SALES_CHANNEL_MIGRATION = `
- DROP TABLE IF EXISTS entity_sales_channel CASCADE;
- CREATE TABLE IF NOT EXISTS entity_sales_channel (
- esc_id bigint PRIMARY KEY,
- esc_sales_channel_type_id bigint NOT NULL CONSTRAINT sales_channel_type_fk REFERENCES sales_channel_type,
- esc_entity_id bigint NOT NULL CONSTRAINT entity_fk REFERENCES entity,
- esc_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- esc_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- esc_account_id text,
- esc_active boolean DEFAULT FALSE NOT NULL,
- esc_external_location_id text,
- esc_name text NOT NULL,
- esc_taxable boolean DEFAULT TRUE NOT NULL,
- esc_price_level_id bigint REFERENCES cohort_price_level ON UPDATE CASCADE ON DELETE RESTRICT,
- esc_external_integration_enabled boolean DEFAULT FALSE NOT NULL,
- esc_external_integration_attempt integer DEFAULT 0 NOT NULL,
- esc_external_address_line_1 text,
- esc_external_address_line_2 text,
- esc_external_address_city text,
- esc_external_address_state text,
- esc_external_address_zip text,
- esc_external_requestor_name text,
- esc_external_requestor_email text,
- esc_external_merchant_decision_maker_email text,
- esc_sftp_credentials jsonb,
- esc_configuration jsonb,
- esc_auto_add_new_departments boolean DEFAULT TRUE NOT NULL,
- esc_allow_negative_inventory boolean DEFAULT FALSE
- );
-
- CREATE INDEX IF NOT EXISTS entity_sales_channel_type_index ON entity_sales_channel (esc_sales_channel_type_id);
-
- CREATE INDEX IF NOT EXISTS entity_sales_channel_price_level_id_idx ON entity_sales_channel (esc_price_level_id);
-
- CREATE INDEX IF NOT EXISTS entity_sales_channel_sales_channel_type_id_idx ON entity_sales_channel (esc_sales_channel_type_id);
-
- CREATE UNIQUE INDEX IF NOT EXISTS entity_sales_channel_entity_id_sales_channel_type_id_uindex ON entity_sales_channel (esc_entity_id, esc_sales_channel_type_id)
- WHERE (esc_sales_channel_type_id = ANY (ARRAY[(1)::bigint, (3)::bigint, (4)::bigint, (6)::bigint, (7)::bigint, (8)::bigint, (9)::bigint, (10)::bigint, (13)::bigint, (14)::bigint, (18)::bigint, (17)::bigint]));`;
-
-const COHORT_ITEM_TAG_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item_tag CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item_tag (
- cit_id bigint CONSTRAINT cohort_item_tag_pk PRIMARY KEY,
- cit_cohort_item_id bigint NOT NULL CONSTRAINT cohort_item_tag_cohort_item_id_fk REFERENCES cohort_item ON UPDATE CASCADE ON DELETE CASCADE,
- cit_tag_id integer NOT NULL CONSTRAINT cohort_item_tag_tag_id_fk REFERENCES entity_tag ON UPDATE CASCADE ON DELETE CASCADE,
- cit_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- cit_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- cit_changed_by varchar(255),
- cit_cohort_id bigint CONSTRAINT cohort_item_tag_cohort_id_fk REFERENCES cohort,
- CONSTRAINT cohort_item_tag_pk_2 UNIQUE (cit_cohort_item_id, cit_tag_id)
- );`;
-
-const COHORT_ITEM_BARCODE_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item_barcode CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item_barcode (
- cib_cohort_item_id bigint NOT NULL CONSTRAINT cohort_item_barcode_cohort_item_id_fk REFERENCES cohort_item ON UPDATE CASCADE ON DELETE CASCADE,
- cib_barcode varchar(255) NOT NULL,
- cib_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- cib_cohort_id bigint CONSTRAINT cohort_item_barcode_cohort_id_fk REFERENCES cohort,
- CONSTRAINT cohort_item_barcode_pk PRIMARY KEY (cib_cohort_item_id, cib_barcode)
- );`;
-
-const COHORT_ITEM_VENDOR_ITEM_MIGRATION = `
- DROP TABLE IF EXISTS cohort_item_vendor_item CASCADE;
- CREATE TABLE IF NOT EXISTS cohort_item_vendor_item (
- civi_cohort_item_id bigint NOT NULL CONSTRAINT cohort_item_vendor_item_cohort_item_id_fk REFERENCES cohort_item ON UPDATE CASCADE ON DELETE CASCADE,
- civi_vendor varchar(255) NOT NULL,
- civi_sku varchar(255),
- civi_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- civi_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- civi_changed_by varchar(255),
- civi_cohort_vendor_id bigint NOT NULL CONSTRAINT cohort_item_vendor_item_cohort_vendor_id_fk REFERENCES cohort_vendor ON UPDATE CASCADE,
- civi_cohort_id bigint CONSTRAINT cohort_item_vendor_item_cohort_id_fk REFERENCES cohort,
- CONSTRAINT cohort_item_vendor_item_pk PRIMARY KEY (civi_cohort_item_id, civi_cohort_vendor_id)
- );`;
-
-const ENTITY_SALES_CHANNEL_ITEM_MIGRATION = `
- DROP TABLE IF EXISTS entity_sales_channel_item CASCADE;
- CREATE TABLE IF NOT EXISTS entity_sales_channel_item (
- esci_id bigint PRIMARY KEY,
- esci_entity_sales_channel_id bigint NOT NULL CONSTRAINT entity_sales_channel_fk REFERENCES entity_sales_channel,
- esci_entity_item_id bigint NOT NULL CONSTRAINT entity_item_fk REFERENCES entity_item ON UPDATE CASCADE ON DELETE CASCADE,
- esci_active boolean DEFAULT TRUE NOT NULL,
- esci_created_at timestamp with time zone DEFAULT NOW() NOT NULL,
- esci_updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
- esci_external_item_id text,
- esci_entity_id bigint CONSTRAINT entity_sales_channel_item_entity_id_fk REFERENCES entity,
- CONSTRAINT entity_sales_channel_item_external_item_id_unique UNIQUE (esci_entity_sales_channel_id, esci_external_item_id),
- CONSTRAINT unique_entity_sales_channel_item UNIQUE (esci_entity_sales_channel_id, esci_entity_item_id)
- );`;
-
-const CASBIN_MIGRATION = `
- CREATE TABLE IF NOT EXISTS casbin_rule_role (
- crr_id serial PRIMARY KEY,
- crr_ptype varchar(100) NOT NULL,
- crr_v0 varchar(100),
- crr_v1 varchar(100),
- crr_v2 varchar(100),
- crr_v3 varchar(100),
- crr_v4 varchar(100),
- crr_v5 varchar(100),
- CONSTRAINT ptype_is_p_v1_number CHECK (((crr_ptype)::text <> 'p'::text) OR ((crr_v1 IS NOT NULL) AND ((crr_v1)::text ~ '^[0-9]+$'::text)))
- );
-
- CREATE TABLE IF NOT EXISTS casbin_rule_user (
- cru_id serial PRIMARY KEY,
- cru_ptype varchar(100) NOT NULL,
- cru_v0 varchar(100),
- cru_v1 varchar(100),
- cru_v2 varchar(100),
- cru_v3 varchar(100),
- cru_v4 varchar(100),
- cru_v5 varchar(100),
- CONSTRAINT ptype_is_p_v1_number CHECK (((cru_ptype)::text <> 'p'::text) OR ((cru_v1 IS NOT NULL) AND ((cru_v1)::text ~ '^[0-9]+$'::text)))
- );
-
- CREATE INDEX IF NOT EXISTS casbin_rule_v0_index ON casbin_rule_role (crr_v0);
-
- CREATE INDEX IF NOT EXISTS casbin_rule_v1_index ON casbin_rule_role (crr_v1);
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_v0_v2_uindex ON casbin_rule_role (crr_v0, crr_v2)
- WHERE ((crr_ptype)::text = 'g'::text);
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_v2_uindex ON casbin_rule_role (crr_v2)
- WHERE (((crr_ptype)::text = 'g'::text) AND ((crr_v1)::text = 'OWNER'::text));
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_pos_register_uindex ON casbin_rule_role (crr_v0, crr_v1)
- WHERE (((crr_ptype)::text = 'g'::text) AND ((crr_v1)::text = 'POS_REGISTER'::text));
-
- CREATE INDEX IF NOT EXISTS casbin_rule_v0_index ON casbin_rule_user (cru_v0);
-
- CREATE INDEX IF NOT EXISTS casbin_rule_v1_index ON casbin_rule_user (cru_v1);
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_v0_v2_uindex ON casbin_rule_user (cru_v0, cru_v2)
- WHERE ((cru_ptype)::text = 'g'::text);
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_v2_uindex ON casbin_rule_user (cru_v2)
- WHERE (((cru_ptype)::text = 'g'::text) AND ((cru_v1)::text = 'OWNER'::text));
-
- CREATE UNIQUE INDEX IF NOT EXISTS casbin_rule_pos_register_uindex ON casbin_rule_user (cru_v0, cru_v1)
- WHERE (((cru_ptype)::text = 'g'::text) AND ((cru_v1)::text = 'POS_REGISTER'::text));
-`;
-
-const ENTITY_MINIMUM_PRICE_SOURCE_TYPE = `
- DROP TABLE IF EXISTS entity_minimum_price_source_type CASCADE;
- CREATE TABLE IF NOT EXISTS entity_minimum_price_source_type (
- empst_type VARCHAR(255) NOT NULL CONSTRAINT entity_minimum_price_source_type_pk PRIMARY KEY
- );
-`;
-
-const ENTITY_ADDRESS_NULLABLE_MIGRATION = `
- ALTER TABLE entity
- ALTER COLUMN ey_address DROP NOT NULL;
-`;
-
-const COHORT_ID_SYNC_MIGRATION_CIB_ESCI_CIVIN_CIVI_CIT = `
- -- Department Group
- ALTER TABLE department_group
- DROP CONSTRAINT IF EXISTS department_group_cohort_id_id_key;
-
- ALTER TABLE department_group
- ADD CONSTRAINT department_group_cohort_id_id_key UNIQUE (dg_cohort_id, dg_id);
-
- -- Department
- ALTER TABLE department
- DROP CONSTRAINT IF EXISTS department_cohort_id_id_key;
-
- ALTER TABLE department
- ADD CONSTRAINT department_cohort_id_id_key UNIQUE (dp_cohort_id, dp_id);
-
- DROP INDEX IF EXISTS department_department_group_id_index;
-
- ALTER TABLE department
- DROP CONSTRAINT IF EXISTS department_department_group_id_fkey;
-
- DROP INDEX IF EXISTS department_cohort_id_department_group_id_index;
-
- CREATE INDEX department_cohort_id_department_group_id_index ON department (dp_cohort_id, dp_department_group_id);
-
- ALTER TABLE department
- DROP CONSTRAINT IF EXISTS department_department_group_cohort_id_id_fk;
-
- ALTER TABLE department
- ADD CONSTRAINT department_department_group_cohort_id_id_fk FOREIGN KEY (dp_cohort_id, dp_department_group_id) REFERENCES department_group (dg_cohort_id, dg_id) ON UPDATE CASCADE;
-
- -- Cohort Item
- ALTER TABLE cohort_item
- DROP CONSTRAINT IF EXISTS cohort_item_department_id_fk;
-
- ALTER TABLE cohort_item
- DROP CONSTRAINT IF EXISTS cohort_item_department_cohort_id_id_fk;
-
- ALTER TABLE cohort_item
- ADD CONSTRAINT cohort_item_department_cohort_id_id_fk FOREIGN KEY (ci_cohort_id, ci_department) REFERENCES department (dp_cohort_id, dp_id) ON UPDATE CASCADE;
-
- ALTER TABLE cohort_item
- DROP CONSTRAINT IF EXISTS cohort_item_cohort_id_id_key;
-
- ALTER TABLE cohort_item
- ADD CONSTRAINT cohort_item_cohort_id_id_key UNIQUE (ci_cohort_id, ci_id);
-
- -- Cohort Item Barcode
- ALTER TABLE cohort_item_barcode
- ALTER COLUMN cib_cohort_id SET NOT NULL;
-
- ALTER TABLE cohort_item_barcode
- DROP CONSTRAINT IF EXISTS cohort_item_barcode_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_barcode
- DROP CONSTRAINT IF EXISTS cohort_item_barcode_cohort_id_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_barcode
- ADD CONSTRAINT cohort_item_barcode_cohort_id_cohort_item_id_fk FOREIGN KEY (cib_cohort_id, cib_cohort_item_id) REFERENCES cohort_item (ci_cohort_id, ci_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- -- Tag
- ALTER TABLE entity_tag
- DROP CONSTRAINT IF EXISTS entity_tag_cohort_id_id_key;
-
- ALTER TABLE entity_tag
- ADD CONSTRAINT entity_tag_cohort_id_id_key UNIQUE (et_cohort_id, et_id);
-
- -- Cohort Item Tag
- ALTER TABLE cohort_item_tag
- ALTER COLUMN cit_cohort_id SET NOT NULL;
-
- ALTER TABLE cohort_item_tag
- DROP CONSTRAINT IF EXISTS cohort_item_tag_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_tag
- DROP CONSTRAINT IF EXISTS cohort_item_tag_cohort_id_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_tag
- ADD CONSTRAINT cohort_item_tag_cohort_id_cohort_item_id_fk FOREIGN KEY (cit_cohort_id, cit_cohort_item_id) REFERENCES cohort_item (ci_cohort_id, ci_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- ALTER TABLE cohort_item_tag
- DROP CONSTRAINT IF EXISTS cohort_item_tag_tag_id_fk;
-
- ALTER TABLE cohort_item_tag
- DROP CONSTRAINT IF EXISTS cohort_item_tag_cohort_id_tag_id_fk;
-
- ALTER TABLE cohort_item_tag
- ADD CONSTRAINT cohort_item_tag_cohort_id_tag_id_fk FOREIGN KEY (cit_cohort_id, cit_tag_id) REFERENCES entity_tag (et_cohort_id, et_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- -- Cohort Item Vendor Item
- ALTER TABLE cohort_item_vendor_item
- ALTER COLUMN civi_cohort_id SET NOT NULL;
-
- ALTER TABLE cohort_item_vendor_item
- DROP CONSTRAINT IF EXISTS cohort_item_vendor_item_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_vendor_item
- DROP CONSTRAINT IF EXISTS cohort_item_vendor_item_cohort_item_id_cohort_id_fk;
-
- ALTER TABLE cohort_item_vendor_item
- DROP CONSTRAINT IF EXISTS cohort_item_vendor_item_cohort_id_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_vendor_item
- ADD CONSTRAINT cohort_item_vendor_item_cohort_id_cohort_item_id_fk FOREIGN KEY (civi_cohort_id, civi_cohort_item_id) REFERENCES cohort_item (ci_cohort_id, ci_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- -- Cohort Item Vintage
- ALTER TABLE cohort_item_vintage
- ALTER COLUMN civ_cohort_id SET NOT NULL;
-
- ALTER TABLE cohort_item_vintage
- DROP CONSTRAINT IF EXISTS cohort_item_vintage_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_vintage
- DROP CONSTRAINT IF EXISTS cohort_item_vintage_cohort_item_id_cohort_id_fk;
-
- ALTER TABLE cohort_item_vintage
- DROP CONSTRAINT IF EXISTS cohort_item_vintage_cohort_id_cohort_item_id_fk;
-
- ALTER TABLE cohort_item_vintage
- ADD CONSTRAINT cohort_item_vintage_cohort_id_cohort_item_id_fk FOREIGN KEY (civ_cohort_id, civ_cohort_item_id) REFERENCES cohort_item (ci_cohort_id, ci_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- -- Entity Item
- ALTER TABLE entity_item
- DROP CONSTRAINT IF EXISTS entity_item_entity_id_id_key;
-
- ALTER TABLE entity_item
- ADD CONSTRAINT entity_item_entity_id_id_key UNIQUE (ei_entity_id, ei_id);
-
- -- Entity Sales Channel
- ALTER TABLE entity_sales_channel
- DROP CONSTRAINT IF EXISTS entity_sales_channel_entity_id_id_key;
-
- ALTER TABLE entity_sales_channel
- ADD CONSTRAINT entity_sales_channel_entity_id_id_key UNIQUE (esc_entity_id, esc_id);
-
- -- Entity Sales Channel Item
- ALTER TABLE entity_sales_channel_item
- ALTER COLUMN esci_entity_id SET NOT NULL;
-
- DROP INDEX IF EXISTS entity_sales_channel_item_entity_item_id_index;
-
- DROP INDEX IF EXISTS entity_sales_channel_item_entity_id_entity_item_id_index;
-
- CREATE INDEX entity_sales_channel_item_entity_id_entity_item_id_index ON entity_sales_channel_item (esci_entity_id, esci_entity_item_id);
-
- ALTER TABLE entity_sales_channel_item
- DROP CONSTRAINT IF EXISTS entity_item_fk;
-
- ALTER TABLE entity_sales_channel_item
- ADD CONSTRAINT entity_item_fk FOREIGN KEY (esci_entity_id, esci_entity_item_id) REFERENCES entity_item (ei_entity_id, ei_id) ON UPDATE CASCADE ON DELETE CASCADE;
-
- ALTER TABLE entity_sales_channel_item
- DROP CONSTRAINT IF EXISTS entity_sales_channel_fk;
-
- ALTER TABLE entity_sales_channel_item
- ADD CONSTRAINT entity_sales_channel_fk FOREIGN KEY (esci_entity_id, esci_entity_sales_channel_id) REFERENCES entity_sales_channel (esc_entity_id, esc_id);
-`;
-
-export const MIGRATIONS: Migration[] = [
- {
- id: "transaction_item_cost_type",
- script: TRANSACTION_ITEM_COST_TYPE_MIGRATION,
- },
- {
- id: "cohort",
- script: COHORT_MIGRATION,
- },
- {
- id: "cohort_item_size_unit",
- script: COHORT_ITEM_SIZE_UNIT_MIGRATION,
- },
- {
- id: "department_group",
- script: DEPARTMENT_GROUP_MIGRATION,
- },
- {
- id: "department",
- script: DEPARTMENT_MIGRATION,
- },
- {
- id: "item_type",
- script: ITEM_TYPE_MIGRATION,
- },
- {
- id: "cohort_item",
- script: COHORT_ITEM_MIGRATION,
- },
- {
- id: "cohort_vendor",
- script: COHORT_VENDOR_MIGRATION,
- },
- {
- id: "entity_minimum_price_source_type",
- script: ENTITY_MINIMUM_PRICE_SOURCE_TYPE,
- },
- {
- id: "cohort_item_vintage",
- script: COHORT_ITEM_VINTAGE_MIGRATION,
- },
- {
- id: "address",
- script: ADDRESS_MIGRATION,
- },
- {
- id: "entity",
- script: ENTITY_MIGRATION,
- },
- {
- id: "entity_item",
- script: ENTITY_ITEM_MIGRATION,
- },
- {
- id: "entity_tag",
- script: ENTITY_TAG_MIGRATION,
- },
- {
- id: "entity_attribute",
- script: ENTITY_ATTRIBUTE_MIGRATION,
- },
- {
- id: "entity_configuration",
- script: ENTITY_CONFIGURATION_MIGRATION,
- },
- {
- id: "register",
- script: REGISTER_MIGRATION,
- },
- {
- id: "bill_denomination",
- script: BILL_DENOMINATION_MIGRATION,
- },
- {
- id: "sales_channel_type",
- script: SALES_CHANNEL_TYPE_MIGRATION,
- },
- {
- id: "cohort_price_level",
- script: COHORT_PRICE_LEVEL_MIGRATION,
- },
- {
- id: "entity_sales_channel",
- script: ENTITY_SALES_CHANNEL_MIGRATION,
- },
- {
- id: "cohort_item_tag",
- script: COHORT_ITEM_TAG_MIGRATION,
- },
- {
- id: "cohort_item_barcode",
- script: COHORT_ITEM_BARCODE_MIGRATION,
- },
- {
- id: "cohort_item_vendor_item",
- script: COHORT_ITEM_VENDOR_ITEM_MIGRATION,
- },
- {
- id: "entity_sales_channel_item",
- script: ENTITY_SALES_CHANNEL_ITEM_MIGRATION,
- },
- {
- id: "casbin",
- script: CASBIN_MIGRATION,
- },
- {
- id: "entity_address_nullable",
- script: ENTITY_ADDRESS_NULLABLE_MIGRATION,
- },
- {
- id: "cohort_id_sync_cib_esci_civin_civi_cit",
- script: COHORT_ID_SYNC_MIGRATION_CIB_ESCI_CIVIN_CIVI_CIT,
- },
- // Add more migrations here as needed
-];
diff --git a/src/components/pg-lite/pglite-worker.ts b/src/components/pg-lite/pglite-worker.ts
deleted file mode 100644
index b7c62e13..00000000
--- a/src/components/pg-lite/pglite-worker.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { PGlite } from "@electric-sql/pglite";
-import { worker } from "@electric-sql/pglite/worker";
-import { MIGRATIONS } from "./migration";
-import { PGLITE_OPTIONS } from "./PgliteOptions";
-
-void worker({
- async init() {
- // Create and return a PGlite instance
- const pg = await PGlite.create(PGLITE_OPTIONS);
-
- // Exempt from the migration convention
- await pg.exec(`
- CREATE TABLE IF NOT EXISTS migrations (
- id TEXT PRIMARY KEY,
- applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- );
- `);
- await pg.exec(`
- SET session_replication_role = 'replica';
- `);
- for (const migration of MIGRATIONS) {
- const res = await pg.query(
- "SELECT 1 FROM migrations WHERE id = $1::text",
- [migration.id],
- );
- if (res.rows.length === 0) {
- console.info(`Applying migration: ${migration.id}`);
- await pg.transaction(async (tx) => {
- await tx.exec(migration.script);
- await tx.query(
- "INSERT INTO migrations (id) VALUES ($1::text) ON CONFLICT DO NOTHING",
- [migration.id],
- );
- });
- } else {
- console.info(`Migration already applied: ${migration.id}`);
- }
- }
-
- return pg;
- },
-});
diff --git a/src/components/pg-lite/queries/RetrieveItemsByUpc.ts b/src/components/pg-lite/queries/RetrieveItemsByUpc.ts
deleted file mode 100644
index 692d7eab..00000000
--- a/src/components/pg-lite/queries/RetrieveItemsByUpc.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { query } from "@electric-sql/pglite/template";
-import { CohortItem } from "../table-types/CohortItem";
-import { Department } from "../table-types/Department";
-import { EntityItem } from "../table-types/EntityItem";
-
-export type RetrieveItemsByUpc = CohortItem & EntityItem & Department;
-
-export const RetrieveItemsByUpcQuery = (
- entityId: number,
- upc: string | null,
- entityItemId: number[] | null,
-) => query`
- SELECT * FROM
- entity_item ei
- JOIN cohort_item ci ON ei.ei_cohort_item_id = ci.ci_id
- JOIN department dp ON ci.ci_department = dp.dp_id
- WHERE
- ei.ei_entity_id = ${entityId}
- AND ei.ei_sellable
- AND (${upc}::text IS NULL OR EXISTS (
- SELECT
- 1
- FROM
- cohort_item_barcode cib
- WHERE
- cib.cib_cohort_item_id = ci.ci_id
- AND cib.cib_barcode LIKE ${upc}::text))
- AND (${entityItemId}::BIGINT[] IS NULL OR ei.ei_id = ANY(${entityItemId}))
- LIMIT 100
-`;
diff --git a/src/components/pg-lite/table-types/CohortItem.ts b/src/components/pg-lite/table-types/CohortItem.ts
deleted file mode 100644
index 71ee391c..00000000
--- a/src/components/pg-lite/table-types/CohortItem.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BigDecimal } from "src/big-decimal/BigDecimal";
-
-export type CohortItem = {
- ci_id: number;
- ci_cohort_id: number;
- ci_name: string;
- ci_case_quantity: number;
- ci_size: BigDecimal | null; // numeric(10, 4)
- ci_size_unit: string | null;
- ci_alcohol_by_volume: string | null;
- ci_deposit_multiplier: number;
- ci_environment_fee_multiplier: number;
- ci_parent_cohort_item_id: number | null;
- ci_parent_quantity: number | null;
- ci_notes: string | null;
- ci_changed_by: string | null;
- ci_created_at: Date;
- ci_updated_at: Date;
- ci_migration_id: string | null;
- ci_parent_migration_id: string | null;
- ci_department: number;
- ci_brand: string | null;
- ci_pack_size: number | null;
- ci_alcoholic: boolean;
- ci_vintage: string | null;
- ci_item_type_id: number;
- ci_version: number;
-};
diff --git a/src/components/pg-lite/table-types/Department.ts b/src/components/pg-lite/table-types/Department.ts
deleted file mode 100644
index b348ad7b..00000000
--- a/src/components/pg-lite/table-types/Department.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export type Department = {
- dp_name: string;
- dp_tax: string; // numeric(38, 6)
- dp_bottledeposit: string; // numeric(38, 2)
- dp_environmentfee: string; // numeric(38, 2)
- dp_updated_at: Date;
- dp_id: number;
- dp_cohort_id: number | null;
- dp_has_revenue: boolean;
- dp_department_group_id: number;
- dp_migration_id: string | null;
-};
diff --git a/src/components/pg-lite/table-types/EntityItem.ts b/src/components/pg-lite/table-types/EntityItem.ts
deleted file mode 100644
index f42560ba..00000000
--- a/src/components/pg-lite/table-types/EntityItem.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-export type EntityItem = {
- ei_id: number;
- ei_entity_id: number;
- ei_cohort_item_id: number;
- ei_price: string; // numeric(10, 2)
- ei_minimum_price: string | null; // numeric(10, 2)
- ei_cost: string | null; // numeric(10, 2)
- ei_discount_allowed: boolean;
- ei_quantity: string; // numeric(10, 4)
- ei_aisle_location: string | null;
- ei_fridge_location: string | null;
- ei_last_quantity_received: number | null;
- ei_changed_by: string | null;
- ei_created_at: Date;
- ei_updated_at: Date;
- ei_migration_id: string | null;
- ei_last_order_date: Date | null;
- ei_exclusive: boolean;
- ei_case_cost: string | null; // numeric(10, 2)
- ei_variable_cost_percent: string | null; // numeric(10, 2)
- ei_last_cohort_vendor_id: number | null;
- ei_preferred_cohort_vendor_id: number | null;
- ei_average_cost: string | null; // numeric(10, 4)
- ei_sellable: boolean;
- ei_version: number;
- ei_cohort_item_vintage_id: string | null;
- ei_true_cost: string | null; // numeric(10, 2)
-};
diff --git a/src/components/po/PurchaseOrderCandidateItems.test.tsx b/src/components/po/PurchaseOrderCandidateItems.test.tsx
index 1ca54336..d71113be 100644
--- a/src/components/po/PurchaseOrderCandidateItems.test.tsx
+++ b/src/components/po/PurchaseOrderCandidateItems.test.tsx
@@ -665,7 +665,6 @@ describe("Data Management Tests", () => {
mockCaptureException(err);
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
queryClient,
mockPurchaseOrder.entities,
@@ -733,7 +732,6 @@ describe("Data Management Tests", () => {
mockCaptureException(err);
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
queryClient,
mockPurchaseOrder.entities,
diff --git a/src/components/po/PurchaseOrderCandidateItems.tsx b/src/components/po/PurchaseOrderCandidateItems.tsx
index 07d29afc..82c8ef14 100644
--- a/src/components/po/PurchaseOrderCandidateItems.tsx
+++ b/src/components/po/PurchaseOrderCandidateItems.tsx
@@ -239,7 +239,6 @@ export const PurchaseOrderCandidateItems = forwardRef<
[queryClient, toast],
);
- // eslint-disable-next-line react-hooks/exhaustive-deps
const queueItemRefresh = useCallback(
queue<CohortItem["id"]>(refreshItems, {
wait: 0,
diff --git a/src/components/po/PurchaseOrderItemCard.tsx b/src/components/po/PurchaseOrderItemCard.tsx
index ebdf1760..e46ee0d0 100644
--- a/src/components/po/PurchaseOrderItemCard.tsx
+++ b/src/components/po/PurchaseOrderItemCard.tsx
@@ -458,7 +458,6 @@ export const PurchaseOrderItemCard: React.FC<PurchaseOrderItemCardProps> = ({
await refetchPurchaseOrder();
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[bulkUpdatePOItems, shownVendors, toast],
);
@@ -494,7 +493,6 @@ export const PurchaseOrderItemCard: React.FC<PurchaseOrderItemCardProps> = ({
await refetchPurchaseOrder();
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[bulkUpdatePOItems, shownVendors, toast],
);
@@ -786,7 +784,6 @@ export const PurchaseOrderItemCard: React.FC<PurchaseOrderItemCardProps> = ({
];
return columns;
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
poStatus,
hasManageItemDetailPermission,
diff --git a/src/components/po/useItemSalesBatch.tsx b/src/components/po/useItemSalesBatch.tsx
index f5ec523e..eeecd1ef 100644
--- a/src/components/po/useItemSalesBatch.tsx
+++ b/src/components/po/useItemSalesBatch.tsx
@@ -107,14 +107,12 @@ export const useItemSalesBatch = ({
// Get the current requested items
const currentRequestedItems = useMemo(() => {
return Array.from(requestedItems.current);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryResults, requestedItems.current]); // Re-compute whenever any query or the set changes
// Return the cached results for the requested items
const data = useMemo(() => {
//trigger a re-render when the loading states change
return { ...cache.current };
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [allLoadingStates]);
return {
diff --git a/src/components/ui/use-toast.ts b/src/components/ui/use-toast.ts
index fc690081..8468d912 100644
--- a/src/components/ui/use-toast.ts
+++ b/src/components/ui/use-toast.ts
@@ -6,7 +6,7 @@ import type { ToastActionElement, ToastProps } from "@/components/ui/toast";
const TOAST_LIMIT = 1;
const TOAST_REMOVE_DELAY = 1000000;
-type ToasterToast = Omit<ToastProps, "title"> & {
+type ToasterToast = ToastProps & {
id: string;
title?: React.ReactNode;
description?: React.ReactNode;
@@ -135,25 +135,23 @@ function dispatch(action: Action) {
});
}
-type Toast = Omit<ToasterToast, "id"> & {
- id?: string;
-};
+type Toast = Omit<ToasterToast, "id">;
-function toast({ id, ...props }: Toast) {
- const toastId = id || genId();
+function toast({ ...props }: Toast) {
+ const id = genId();
const update = (props: ToasterToast) =>
dispatch({
type: "UPDATE_TOAST",
- toast: { ...props, id: toastId },
+ toast: { ...props, id },
});
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId });
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
dispatch({
type: "ADD_TOAST",
toast: {
...props,
- id: toastId,
+ id,
open: true,
onOpenChange: (open) => {
if (!open) dismiss();
@@ -162,7 +160,7 @@ function toast({ id, ...props }: Toast) {
});
return {
- id: toastId,
+ id: id,
dismiss,
update,
};
diff --git a/src/components/ui/wizard.tsx b/src/components/ui/wizard.tsx
deleted file mode 100644
index 5b499574..00000000
--- a/src/components/ui/wizard.tsx
+++ /dev/null
@@ -1,253 +0,0 @@
-import { ArrowLeft, ArrowRight, CheckCircle } from "lucide-react";
-import React, { ReactNode, useMemo, useState } from "react";
-import { UseFormReturn } from "react-hook-form";
-import { cn } from "src/lib/utils";
-import { Button } from "./button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "./dialog";
-
-export interface WizardStep {
- title: string;
- description?: string;
- content: ReactNode;
- validation?: () => boolean;
-}
-
-export interface WizardProps {
- steps: WizardStep[];
- isOpen: boolean;
- onClose: () => void;
- onComplete: (data?: unknown) => void;
- onReset?: () => void; // Callback for form reset
- title?: string;
- description?: string;
- className?: string;
- showStepIndicator?: boolean;
- showStepTitles?: boolean;
- nextButtonText?: string;
- backButtonText?: string;
- completeButtonText?: string;
- cancelButtonText?: string;
- isLoading?: boolean;
- data?: unknown;
- autoResetOnComplete?: boolean; // Whether to automatically reset after completion
- form: UseFormReturn<any>;
-}
-
-export const Wizard: React.FC<WizardProps> = ({
- steps,
- isOpen,
- onClose,
- onComplete,
- onReset,
- title = "Wizard",
- description = "Complete the steps to proceed",
- className,
- showStepIndicator = true,
- showStepTitles = true,
- nextButtonText = "Next",
- backButtonText = "Back",
- completeButtonText = "Complete",
- cancelButtonText = "Cancel",
- isLoading = false,
- data,
- autoResetOnComplete = true, // Default to true for better UX
- form,
-}) => {
- const [currentStep, setCurrentStep] = useState(0);
- const totalSteps = steps.length;
-
- // Ensure currentStep is within bounds
- const safeCurrentStep = Math.min(Math.max(0, currentStep), totalSteps - 1);
- const currentStepData = steps[safeCurrentStep] ?? {
- validation: () => true,
- content: null,
- };
-
- const watchedFields = form.watch();
- const resetWizard = () => {
- setCurrentStep(0);
- onReset?.();
- };
-
- const handleNext = async () => {
- // Run validation if provided
- if (currentStepData.validation) {
- try {
- const isValid = await currentStepData.validation();
- if (!isValid) {
- return; // Don't proceed if validation fails
- }
- } catch (error) {
- console.error("Validation error:", error);
- return;
- }
- }
-
- if (currentStep < totalSteps - 1) {
- setCurrentStep(currentStep + 1);
- } else {
- // Call onComplete with the data
- onComplete(data);
-
- // Automatically reset and close if enabled
- if (autoResetOnComplete) {
- resetWizard();
- onClose();
- }
- }
- };
-
- const handleBack = () => {
- if (currentStep > 0) {
- setCurrentStep(currentStep - 1);
- }
- };
-
- const handleClose = () => {
- resetWizard();
- onClose();
- };
-
- const canGoToNextStep = useMemo(() => {
- return currentStepData.validation?.() ?? true;
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [currentStepData, watchedFields]);
-
- return (
- <Dialog open={isOpen} onOpenChange={handleClose}>
- <DialogContent
- className={cn("sm:max-w-3xl max-h-[90vh] overflow-y-auto", className)}
- >
- <DialogHeader>
- <DialogTitle className="flex items-center gap-2">
- <CheckCircle className="h-5 w-5 text-green-500" />
- <span>{title}</span>
- <span className="text-sm font-normal text-gray-500">
- ({safeCurrentStep + 1} of {totalSteps})
- </span>
- </DialogTitle>
- <DialogDescription>{description}</DialogDescription>
- </DialogHeader>
-
- <div className="space-y-6">
- {/* Step Progress Indicator */}
- {showStepIndicator && (
- <div className="flex items-center justify-between">
- {Array.from({ length: totalSteps }).map((_, index) => (
- <div
- key={index}
- className={`flex items-center ${
- index < totalSteps - 1 ? "flex-1" : ""
- }`}
- >
- <div
- className={`flex items-center justify-center w-8 h-8 rounded-full text-sm font-medium ${
- index <= currentStep
- ? "bg-blue-500 text-white"
- : "bg-gray-100 text-gray-600"
- }`}
- >
- {index + 1}
- </div>
- {showStepTitles && (
- <span
- className={`ml-2 text-sm font-medium ${
- index <= currentStep ? "text-blue-500" : "text-gray-500"
- }`}
- >
- {steps[index]?.title}
- </span>
- )}
- {index < totalSteps - 1 && (
- <div
- className={`flex-1 h-0.5 mx-4 ${
- index < currentStep ? "bg-blue-500" : "bg-gray-200"
- }`}
- />
- )}
- </div>
- ))}
- </div>
- )}
-
- {/* Step Content */}
- <div className="min-h-[400px]">{currentStepData.content}</div>
-
- {/* Navigation */}
- <DialogFooter className="gap-2">
- {currentStep > 0 && (
- <Button
- type="button"
- variant="outline"
- onClick={handleBack}
- disabled={isLoading}
- >
- <ArrowLeft className="h-4 w-4 mr-2" />
- {backButtonText}
- </Button>
- )}
-
- <Button
- type="button"
- variant="outline"
- onClick={handleClose}
- disabled={isLoading}
- >
- {cancelButtonText}
- </Button>
-
- <Button
- type="button"
- onClick={handleNext}
- disabled={!canGoToNextStep || isLoading}
- isLoading={isLoading}
- >
- {currentStep === totalSteps - 1
- ? completeButtonText
- : nextButtonText}
- {currentStep < totalSteps - 1 && (
- <ArrowRight className="h-4 w-4 ml-2" />
- )}
- </Button>
- </DialogFooter>
- </div>
- </DialogContent>
- </Dialog>
- );
-};
-
-// Hook for managing wizard state
-export const useWizard = (steps: WizardStep[]) => {
- const [isOpen, setIsOpen] = useState(false);
- const [data, setData] = useState<unknown>(null);
-
- const openWizard = (initialData?: unknown) => {
- setData(initialData);
- setIsOpen(true);
- };
-
- const closeWizard = () => {
- setIsOpen(false);
- setData(null);
- };
-
- const completeWizard = (finalData?: unknown) => {
- // You can add completion logic here
- closeWizard();
- };
-
- return {
- isOpen,
- openWizard,
- closeWizard,
- completeWizard,
- data,
- };
-};
diff --git a/src/config/phoenix-client.ts b/src/config/phoenix-client.ts
deleted file mode 100644
index 466d25d9..00000000
--- a/src/config/phoenix-client.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
-import qs from "qs";
-import { RegisterType } from "src/context/RegisterProvider";
-import { typeid } from "typeid-js";
-import { firebaseAuth } from "./Firebase/firebase";
-
-export const REQUEST_HEADER_KEY = "X-Request-ID";
-
-export type RequestConfig<TData = unknown> = {
- url?: string;
- method: "get" | "put" | "patch" | "post" | "delete";
- params?: unknown;
- data?: TData;
- responseType?:
- | "arraybuffer"
- | "blob"
- | "document"
- | "json"
- | "text"
- | "stream";
- baseURL?: string;
- signal?: AbortSignal;
- headers?: AxiosRequestConfig["headers"];
- adapter?: AxiosRequestConfig["adapter"];
-};
-/**
- * Subset of AxiosResponse
- */
-export type ResponseConfig<TData = unknown> = {
- data: TData;
- status: number;
- statusText: string;
- headers?: AxiosResponse["headers"];
-};
-
-export const CORE_POS_PATHS = new Set(
- ["/sale", "/signin", "/register/open"].map((s) => s.replace(/\/$/, "")),
-);
-
-export function REDIRECT_TO_CORE_SALE_API() {
- const pathname = window.location.pathname;
- // remove trailing slash if exists
- const path = pathname.replace(/\/$/, "");
-
- if (CORE_POS_PATHS.has(path)) {
- return "CRITICAL";
- }
- return "STABLE";
-}
-
-// Global variable to store current entity ID for axios interceptor
-export let currentEntityId: number | undefined;
-
-// Function to update the entity ID from React context
-export const setCurrentEntityId = (entityId: number | undefined) => {
- currentEntityId = entityId;
-};
-
-export const client = axios.create({
- baseURL: import.meta.env.VITE_APP_PHOENIX_URL,
- paramsSerializer: (params) => qs.stringify(params, { indices: false }),
-});
-client.interceptors.request.use(async (config) => {
- const currentUser = firebaseAuth.currentUser;
-
- config.headers["X-AVAILABILITY"] = REDIRECT_TO_CORE_SALE_API();
- const token = await currentUser?.getIdToken();
- if (token) {
- config.headers.Authorization = `Bearer ${token}`;
- config.headers["X-User-ID"] = currentUser?.uid;
- }
- return config;
-});
-
-// https://github.com/kubb-labs/kubb/commit/87370f5b09df4429e4ee8e3d40494e66f36c9484
-// kubb overrides the baseURL with the first server in the servers array
-client.interceptors.request.use((config) => {
- config.baseURL = import.meta.env.VITE_APP_PHOENIX_URL;
- return config;
-});
-
-client.interceptors.request.use((config) => {
- // Set X-Entity-ID header using the global entity ID
- if (!config.headers.has("X-Entity-ID") && currentEntityId) {
- config.headers["X-Entity-ID"] = currentEntityId;
- }
-
- const entityId = config.headers["X-Entity-ID"];
- if (entityId) {
- const registerJson = JSON.parse(
- // @ts-ignore null can be passed into JSON.parse
- localStorage.getItem(`${entityId}-registerOpen`),
- ) as RegisterType | null;
-
- if (registerJson && registerJson.isRegisterOpen) {
- config.headers["X-Register-ID"] = registerJson.registerNumber;
- }
- }
-
- return config;
-});
-
-client.interceptors.request.use((config) => {
- if (config.url && config.url.includes("items/export")) {
- config.url = config.url.replace("items/export", "items/exports");
- }
- return config;
-});
-client.interceptors.request.use((config) => {
- if (config.headers.has(REQUEST_HEADER_KEY)) {
- return config;
- }
- config.headers[REQUEST_HEADER_KEY] = typeid("req").toString();
- console.log(config.headers[REQUEST_HEADER_KEY], config.url);
- config.params = {
- ...config.params,
- request_id: config.headers[REQUEST_HEADER_KEY],
- };
- return config;
-});
-
-// Send timezone id as a header
-client.interceptors.request.use((config) => {
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
- config.headers["X-Timezone"] = timezone;
- return config;
-});
-
-export const axiosClient = async <
- TData,
- TError = unknown,
- TVariables = unknown,
->(
- config: RequestConfig<TVariables>,
-): Promise<AxiosResponse<TData>> => {
- const promise = client
- .request<TData>({ ...config })
- .catch((e: AxiosError<TError>) => {
- throw e;
- });
-
- return promise;
-};
-
-export default axiosClient;
diff --git a/src/context/AppVersionContext.tsx b/src/context/AppVersionContext.tsx
index eb81ab19..cdac5126 100644
--- a/src/context/AppVersionContext.tsx
+++ b/src/context/AppVersionContext.tsx
@@ -11,57 +11,27 @@ import {
} from "react";
import { toast } from "sonner";
import { useInterval, useLocalStorage } from "usehooks-ts";
-import {
- ORIGIN_DOMAIN_HEADER,
- SERVED_FROM_HEADER,
- STACK_NAME_HEADER,
-} from "utils/constants";
-
-interface VersionInfo {
- version: string;
- originDomain?: string;
- stackName?: string;
- servedFrom?: string;
-}
export const AppVersionContext = createContext<
| {
currentVersion: string;
showingUpdatePrompt: boolean;
- originDomain?: string;
- stackName?: string;
- servedFrom?: string;
}
| undefined
>(undefined);
const UPDATE_INTERVAL_MS = 1000 * 60 * 10; // Check for updates every minute
const VERSION_URL = "/version.json";
-const getNewVersion: () => Promise<VersionInfo> = async () => {
+const getNewVersion: () => Promise<string> = async () => {
try {
console.log("Checking version");
const response = await fetch(VERSION_URL, { cache: "no-store" });
const version = await response.json();
- const headers = response.headers;
- const originDomain = headers.get(ORIGIN_DOMAIN_HEADER);
- const stackName = headers.get(STACK_NAME_HEADER);
- const servedFrom = headers.get(SERVED_FROM_HEADER);
-
- return {
- version: version.version,
- originDomain: originDomain ?? undefined,
- stackName: stackName ?? undefined,
- servedFrom: servedFrom ?? undefined,
- };
+ return version.version;
} catch (error) {
console.warn("Error checking version: ", error);
- return {
- version: "",
- originDomain: undefined,
- stackName: undefined,
- servedFrom: undefined,
- };
+ return "";
}
};
@@ -71,14 +41,9 @@ export const AppVersionProvider = ({
children: React.ReactNode;
}) => {
const isFirstRender = useIsFirstRender();
- const [currentVersion, setCurrentVersion] = useLocalStorage<VersionInfo>(
- "currentVersion-09-17-25",
- {
- version: "",
- originDomain: undefined,
- stackName: undefined,
- servedFrom: undefined,
- },
+ const [currentVersion, setCurrentVersion] = useLocalStorage<string>(
+ "currentVersion-11-19-24",
+ "",
);
// for some reason requires string | number
const [toastId, setToastId] = useState<string | number | undefined>(
@@ -86,7 +51,7 @@ export const AppVersionProvider = ({
);
const displayUpdatePrompt = useCallback(
- (newVersion: VersionInfo) => {
+ (newVersion: string) => {
if (toastId) {
toast.dismiss(toastId);
}
@@ -129,7 +94,7 @@ export const AppVersionProvider = ({
setCurrentVersion(newVersion);
return;
}
- if (newVersion.version !== currentVersion.version) {
+ if (newVersion !== currentVersion) {
displayUpdatePrompt(newVersion);
}
}, [currentVersion, displayUpdatePrompt, setCurrentVersion]);
@@ -150,11 +115,8 @@ export const AppVersionProvider = ({
return (
<AppVersionContext.Provider
value={{
- currentVersion: currentVersion.version,
+ currentVersion,
showingUpdatePrompt: useMemo(() => toastId !== undefined, [toastId]),
- originDomain: currentVersion.originDomain,
- stackName: currentVersion.stackName,
- servedFrom: currentVersion.servedFrom,
}}
>
{children}
diff --git a/src/context/AuthenticationContext/AuthenticationContext.tsx b/src/context/AuthenticationContext/AuthenticationContext.tsx
index a4854997..c9ec0748 100644
--- a/src/context/AuthenticationContext/AuthenticationContext.tsx
+++ b/src/context/AuthenticationContext/AuthenticationContext.tsx
@@ -1,4 +1,3 @@
-import { useStatsigClient } from "@statsig/react-bindings";
import {
firebaseAuth,
firebaseAuthOverridden,
@@ -70,7 +69,6 @@ export const AuthContextProvider = ({
}: AuthContextProviderProps) => {
const [isLoading, setIsLoading] = useState(true);
const posthog = usePostHog();
- const { client: statsigClient } = useStatsigClient();
const [user, setUser] = useFirebaseSyncedUser(
firebaseAuth,
useCallback(() => setIsLoading(false), []),
@@ -195,7 +193,6 @@ export const AuthContextProvider = ({
if (!user?.uid) {
posthog.reset();
Sentry.setUser(null);
- statsigClient.updateUserSync({ userID: undefined });
setAuthenticated(false);
return;
}
@@ -219,17 +216,11 @@ export const AuthContextProvider = ({
ip_address: "{{auto}}",
});
- statsigClient.updateUserSync({
- userID: user.uid,
- email: user.email ?? undefined,
- });
-
window.Atlas.call("identify", {
userId: user.uid,
name: user.displayName,
email: user.email,
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [posthog, setAuthenticated, user?.displayName, user?.email, user?.uid]);
useEffect(() => {
diff --git a/src/context/DepartmentContext.tsx b/src/context/DepartmentContext.tsx
index 7a4f5d24..84a62020 100644
--- a/src/context/DepartmentContext.tsx
+++ b/src/context/DepartmentContext.tsx
@@ -100,8 +100,8 @@ export const DepartmentProvider = ({ children }: { children: ReactNode }) => {
// need to find a better way to do this, maybe register callbacks on entity changes in EntityProvider
useEffect(() => {
refetch();
- // causes infinite re-render, only want to run on cohortId change
// eslint-disable-next-line react-hooks/exhaustive-deps
+ // causes infinite re-render, only want to run on cohortId change
}, [cohortId]);
const value = useMemo(
diff --git a/src/context/EntityProvider.tsx b/src/context/EntityProvider.tsx
index 7830ce03..cc3e03ea 100644
--- a/src/context/EntityProvider.tsx
+++ b/src/context/EntityProvider.tsx
@@ -1,6 +1,5 @@
-import { useStatsigClient } from "@statsig/react-bindings";
import { useQueryClient } from "@tanstack/react-query";
-import { captureException, setTag } from "config/sentry/TransformitySentry";
+import { setTag } from "config/sentry/TransformitySentry";
import { usePostHog } from "posthog-js/react";
import {
createContext,
@@ -142,7 +141,6 @@ export const EntityContextProvider = ({
);
const [entity, setEntity] = useState<EntityDto>();
const posthog = usePostHog();
- const { client: statsigClient } = useStatsigClient();
const queryClient = useQueryClient();
const entityRetrieve = useCallback(
@@ -218,28 +216,8 @@ export const EntityContextProvider = ({
name: entity.cohortId,
id: entity.cohortId,
});
-
- try {
- const updatedUser = {
- ...statsigClient.getContext().user,
- customIDs: {
- entityId: entity.id.toString(),
- cohortId: entity.cohortId.toString(),
- },
- };
- statsigClient.dataAdapter
- .prefetchData(updatedUser)
- .then(() => {
- statsigClient.updateUserSync(updatedUser);
- })
- .catch((error) => {
- captureException(error);
- });
- } catch (error) {
- captureException(error);
- }
}
- }, [entity, posthog, statsigClient]);
+ }, [entity, posthog]);
useEffect(() => {
if (entity && user) {
diff --git a/src/context/InvoiceContext.tsx b/src/context/InvoiceContext.tsx
index e384107b..8009cef6 100644
--- a/src/context/InvoiceContext.tsx
+++ b/src/context/InvoiceContext.tsx
@@ -255,7 +255,6 @@ export const InvoiceProvider: React.FC<InvoiceProviderProps> = ({
invoice.invoiceItems[itemIndex] = item;
setInvoice(structuredClone(invoice));
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[invoice, postInvoiceItem],
);
diff --git a/src/context/Sales/SalesContext.tsx b/src/context/Sales/SalesContext.tsx
index e6e83632..bdee7490 100644
--- a/src/context/Sales/SalesContext.tsx
+++ b/src/context/Sales/SalesContext.tsx
@@ -1,4 +1,3 @@
-import { RetrieveItemsByUpc } from "components/pg-lite/queries/RetrieveItemsByUpc";
import { GovernmentID } from "model/data-contracts";
import { LineItem } from "pages/SalePage/SalePageUtils";
import { createContext, useContext } from "react";
@@ -8,11 +7,10 @@ import {
DraftTransactionInput,
DraftTransactionItemInput,
DraftTransactionMutationResponse,
+ EntityItemDetail,
LoyaltyCustomer,
TransactionId,
- TransactionPaymentForm,
} from "src/generated";
-import { EntitySalesChannelPaymentMethod } from "src/spring-generated";
import { SalesPaymentContextType } from "./SalesPaymentContext";
export type DraftTransactionArgs = Partial<
@@ -24,9 +22,6 @@ export type PricingRequestOptions = {
requestedDiscount?: Discount;
requestTaxExempt: boolean;
requestedCustomer?: LoyaltyCustomer;
- paymentMethodId?: string;
- overriddenPriceLevel?: number;
- hasOverriddenPriceLevel?: boolean;
};
export interface SalesContextType {
@@ -42,7 +37,7 @@ export interface SalesContextType {
>;
addSingleItemToCart: (
itemDetailz:
- | RetrieveItemsByUpc
+ | EntityItemDetail
| Omit<DraftTransactionItemInput, "transactionId">,
quantity: number,
) => void;
@@ -58,14 +53,11 @@ export interface SalesContextType {
id: SalesContextType["governmentID"],
) => void | Promise<void>;
customer?: LoyaltyCustomer;
- transactionTotalPrice: (options?: {
- items?: SalesContextType["items"];
- paymentMethodId?: string;
- }) => number;
+ transactionTotalPrice: (itemz?: SalesContextType["items"]) => number;
clearCart: () => Promise<void>;
- resetCartToCurrentItems: () => Promise<void>;
+ resetCartToCurrentItems: () => void;
handleRetrievedItems: (
- items: RetrieveItemsByUpc[],
+ items: EntityItemDetail[],
quantity: number,
) => Promise<void>;
retrieveItemsLikeUpc: (
@@ -73,17 +65,14 @@ export interface SalesContextType {
exact?: boolean,
quantity?: number,
) => void;
- multipleChoices:
- | { items: RetrieveItemsByUpc[]; quantity: number }
- | undefined;
+ multipleChoices: { items: EntityItemDetail[]; quantity: number } | undefined;
setMultipleChoices: React.Dispatch<
React.SetStateAction<
- { items: RetrieveItemsByUpc[]; quantity: number } | undefined
+ { items: EntityItemDetail[]; quantity: number } | undefined
>
>;
deviceBusy: boolean;
setDeviceBusy: React.Dispatch<React.SetStateAction<boolean>>;
- isCalculatingBackgroundPaymentMethodTotals: boolean;
transactionId?: number;
setTransactionId: (
transactionId?: TransactionId,
@@ -94,19 +83,6 @@ export interface SalesContextType {
isCalculatingCartPrice: boolean;
isGetCartPricingError: boolean;
setItemsInCart: (items: Map<number, LineItem>) => Promise<void>;
- paymentMethodTypeToPaymentMethod: Record<
- string,
- Array<EntitySalesChannelPaymentMethod>
- >;
- hasMultiplePriceLevelsOnSalesChannel: boolean;
- calculateMethodsWithPrices: (
- paymentForm: TransactionPaymentForm,
- ) => Array<{ method: EntitySalesChannelPaymentMethod; total: number }>;
- findBestPaymentMethod: (
- paymentMethods: EntitySalesChannelPaymentMethod[] | undefined,
- defaultPaymentMethodId?: string,
- ) => EntitySalesChannelPaymentMethod | null;
- setSkipSetItemsInCart: (skip: boolean) => void;
}
export const SalesContext = createContext<SalesContextType | undefined>(
@@ -119,7 +95,7 @@ export const getTotalQuantity = (
return [...items.values()].reduce(
(partialSum, a) =>
// DEPOSIT should not count against total quantity
- partialSum + (!a.item?.dp_has_revenue ? 0 : a.quantity),
+ partialSum + (!a.item?.cohortItem.department.hasRevenue ? 0 : a.quantity),
0,
);
};
diff --git a/src/context/Sales/SalesContextProvider.tsx b/src/context/Sales/SalesContextProvider.tsx
index 2de10f70..6db69bf3 100644
--- a/src/context/Sales/SalesContextProvider.tsx
+++ b/src/context/Sales/SalesContextProvider.tsx
@@ -1,12 +1,7 @@
import { useToast } from "@chakra-ui/react";
-import { usePGlite } from "@electric-sql/pglite-react";
import { useQueryClient } from "@tanstack/react-query";
import { useDebounce } from "@uidotdev/usehooks";
import { CanceledError, isAxiosError } from "axios";
-import {
- type RetrieveItemsByUpc,
- RetrieveItemsByUpcQuery,
-} from "components/pg-lite/queries/RetrieveItemsByUpc";
import { useSalePageConfig } from "components/SalesScreenComponents/SalePageConfigProvider";
import {
captureException,
@@ -14,38 +9,34 @@ import {
} from "config/sentry/TransformitySentry";
import { isEqual, round } from "lodash-es";
import posthog from "posthog-js";
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { Navigate, useBeforeUnload, useBlocker } from "react-router-dom";
import {
CartDiscountType,
- type Discount,
- type DraftTransactionInput,
- type DraftTransactionItemInput,
+ Discount,
+ DraftTransactionInput,
+ DraftTransactionItemInput,
+ EntityItemDetail,
getCartPricing as getCartPricingRequest,
getItemByIdQueryOptions,
getLoyaltyCustomerQueryOptions,
getTransactionByIdQueryOptions,
- type GovernmentId,
- type LoyaltyCustomer,
- type PricingCartInputItem,
+ GovernmentId,
+ LoyaltyCustomer,
+ PricingCartInputItem,
PricingCartInputItemType,
- type PricingCartOutputItem,
+ PricingCartOutputItem,
retrieveItemsLikeUpcQueryOptions,
- type TransactionCartItem,
- type TransactionId,
- TransactionPaymentForm,
- type UnknownItem,
+ TransactionCartItem,
+ TransactionId,
+ UnknownItem,
useDraftTransaction,
useDraftTransactionItem,
useEmptyCart,
useSetItemsInCart,
} from "src/generated";
import { useGetAllDepartmentsForEntity } from "src/hooks/useGetAllDepartmentsForEntity";
-import {
- EntitySalesChannelPaymentMethod,
- useCreateTransactionHold,
- useSearchEntitySalesChannelPaymentMethods,
-} from "src/spring-generated";
+import { useCreateTransactionHold } from "src/spring-generated";
import { useLocalStorage } from "usehooks-ts";
import Loading from "../../components/Loading";
import {
@@ -53,7 +44,7 @@ import {
convertToPricingCartInputItem,
getDiscountMap,
hasCalculationWarning,
- type LineItem,
+ LineItem,
} from "../../pages/SalePage/SalePageUtils";
import { playFailureSound } from "../../utils/audioUtils";
import {
@@ -62,10 +53,9 @@ import {
} from "../EntityProvider";
import { useRegisterProvider } from "../RegisterProvider";
import {
- type DraftTransactionArgs,
- type PricingRequestOptions,
+ DraftTransactionArgs,
+ PricingRequestOptions,
SalesContext,
- SalesContextType,
} from "./SalesContext";
export interface SalesContextProviderProps {
@@ -108,64 +98,9 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const { id: programId } = useLoyaltyProgramIdOptional();
const [entity, , isEntityLoading] = useEntitySelected();
const toast = useToast();
-
const { departmentMap, departmentKeyMap } = useGetAllDepartmentsForEntity();
- const {
- selectedSalesChannel,
- selectSalesChannel,
- resetSalesChannel,
- overriddenCohortPriceLevel,
- selectOverriddenCohortPriceLevel,
- resetOverriddenCohortPriceLevel,
- } = useSalePageConfig();
-
- // Get payment methods for the current sales channel
- const { data: paymentMethods } = useSearchEntitySalesChannelPaymentMethods(
- {
- entitySalesChannelId: selectedSalesChannel?.id,
- entityId: entity.id,
- isArchived: false,
- },
- {
- query: {
- enabled:
- !!selectedSalesChannel?.id &&
- !!entity.id &&
- selectedSalesChannel.entityId === entity.id,
- },
- },
- );
-
- const paymentMethodTypeToPaymentMethod = useMemo(() => {
- return (
- paymentMethods?.content?.reduce(
- (acc, paymentMethod) => {
- const paymentForm = paymentMethod.paymentMethodType.replace(
- "_",
- " ",
- ) as TransactionPaymentForm;
-
- if (!acc[paymentForm]) {
- acc[paymentForm] = [];
- }
- acc[paymentForm].push(paymentMethod);
- return acc;
- },
- {} as Record<
- TransactionPaymentForm,
- Array<EntitySalesChannelPaymentMethod>
- >,
- ) ??
- ({} as Record<
- TransactionPaymentForm,
- Array<EntitySalesChannelPaymentMethod>
- >)
- );
- }, [paymentMethods]);
-
- // Track the override payment method (defaults to sales channel default, can be overridden)
- // Now managed by the store via useSalePageConfig
-
+ const { selectedSalesChannel, selectSalesChannel, resetSalesChannel } =
+ useSalePageConfig();
const [isTransactionLoading, setTransactionLoading] = useState(true);
const [transactionId, setTransactionId] = useLocalStorage<
TransactionId | undefined
@@ -216,7 +151,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const [items, setItems] = useState<itemT>();
const queryClient = useQueryClient();
- const db = usePGlite();
const itemsUndefined = items === undefined;
const { register } = useRegisterProvider();
@@ -252,13 +186,11 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
if (inputtedTransactionId) {
setTransactionId(inputtedTransactionId);
}
- resetOverriddenCohortPriceLevel();
- setPaymentMethodIdToCartTotal({});
return await draftTransaction({
id: inputtedTransactionId,
});
},
- [draftTransaction, setTransactionId, resetOverriddenCohortPriceLevel],
+ [draftTransaction, setTransactionId],
);
useEffect(() => {
@@ -277,27 +209,19 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
.fetchQuery(getTransactionOptions)
.then(async (res) => {
for (const transactionItem of res.transactionItems) {
- const entityItemOptions = transactionItem.itemId
+ const entityItemOptions = !!transactionItem.itemId
? getItemByIdQueryOptions(transactionItem.itemId)
: undefined;
- const entityItem = entityItemOptions
+ const entityItem = !!entityItemOptions
? await queryClient.fetchQuery(entityItemOptions)
: undefined;
- const options = RetrieveItemsByUpcQuery(
- entity.id,
- null,
- entityItem?.id ? [entityItem.id] : [],
- );
- const eRes = entityItem?.id
- ? await db.query<RetrieveItemsByUpc>(options.query, options.params)
- : undefined;
newItemDetails.set(transactionItem.id, {
...transactionItem,
tax: transactionItem.tax,
taxRate: transactionItem.taxRate ?? 0,
promotionItems: transactionItem.promotionItems,
discount: transactionItem.discount ?? 0,
- item: eRes?.rows?.[0],
+ item: entityItem,
itemId: transactionItem.itemId,
transactionId: transactionId,
department: transactionItem.department ?? 0,
@@ -313,7 +237,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
}
: undefined,
);
-
const transactionCustomerId = res.customerId;
let customerRes: LoyaltyCustomer | undefined;
if (!!transactionCustomerId && programId !== undefined) {
@@ -328,7 +251,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
resetSalesChannel();
} else if (res.salesChannelId !== selectedSalesChannel.id) {
void selectSalesChannel(res.salesChannelId);
-
const lineItemDiscount = customerRes?.lineItemFixedDiscount;
const lineItemDiscountPercent = lineItemDiscount
? lineItemDiscount * 100
@@ -341,19 +263,18 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
}
: undefined;
}
+ await calculateCartPriceRef
+ .current({
+ requestedItems: newItemDetails,
+ requestedCustomer: customerRes,
+ requestTaxExempt: res.taxExempt ?? false,
+ requestedDiscount: !customerRes?.lineItemFixedDiscount
+ ? customerDiscount(customerRes)
+ : undefined,
+ })
+ // no need to do anything. handled in calculateCartPrice
+ .finally(() => undefined);
}
- await calculateCartPriceRef
- .current({
- requestedItems: newItemDetails,
- requestedCustomer: customerRes,
- requestTaxExempt: res.taxExempt ?? false,
- requestedDiscount: !customerRes?.lineItemFixedDiscount
- ? customerDiscount(customerRes)
- : undefined,
- })
- .catch((err) => {
- return Promise.resolve();
- });
})
.catch(async (err) => {
toast({
@@ -379,12 +300,9 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
setOrResetTransactionId,
register.isRegisterOpen,
selectedSalesChannel.id,
- selectOverriddenCohortPriceLevel,
selectSalesChannel,
resetSalesChannel,
programId,
- entity.id,
- db,
]);
// State
@@ -400,7 +318,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
Map<number, Discount>
>(getDiscountMap(items ?? new Map()));
const [multipleChoices, setMultipleChoices] = useState<{
- items: RetrieveItemsByUpc[];
+ items: EntityItemDetail[];
quantity: number;
}>();
const [deviceBusy, setDeviceBusy] = useState(false);
@@ -415,16 +333,9 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
);
const cartDisplayAbortController = useRef<AbortController | null>(null);
const cartPricingAbortController = useRef<AbortController | null>(null);
- const backgroundCalculationAbortController = useRef<AbortController | null>(
- null,
- );
+ const debouncedItems = useDebounce(items, 650);
const [isGetCartPricingError, setIsGetCartPricingError] = useState(false);
const cartPriceCallInProgress = useRef(false);
- const skipSetItemsInCartRef = useRef(false);
-
- const setSkipSetItemsInCart = useCallback((skip: boolean) => {
- skipSetItemsInCartRef.current = skip;
- }, []);
const { mutateAsync: setItemsInCartMutate } = useSetItemsInCart({
mutation: {
@@ -450,19 +361,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
[],
);
- const [paymentMethodIdToCartTotal, setPaymentMethodIdToCartTotal] = useState<
- Record<string, number>
- >({});
-
- const [debouncedItems, debouncedTotals] = useDebounce<
- [Map<number, LineItem> | undefined, Record<string, number> | undefined]
- >([items, paymentMethodIdToCartTotal], 650);
-
- const [
- isCalculatingBackgroundPaymentMethodTotals,
- setIsCalculatingBackgroundPaymentMethodTotals,
- ] = useState(false);
-
const { mutateAsync: createTransactionHold } = useCreateTransactionHold({
mutation: {
onError(e) {
@@ -473,14 +371,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const migrationInProgressRef = useRef(false);
- const hasMultiplePriceLevelsOnSalesChannel = useMemo(() => {
- return (
- new Set(
- (paymentMethods?.content || []).map((pm) => pm.cohortPriceLevelId),
- ).size > 1
- );
- }, [paymentMethods]);
-
useEffect(() => {
const migrateCarts = async () => {
// Prevent concurrent migrations
@@ -520,6 +410,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
extra: { cart, migrationStep: "createTransactionHold" },
});
remainingCarts.push(cart);
+ continue;
}
}
@@ -545,21 +436,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
// Callbacks
const transactionTotalPrice = useCallback(
- (options?: {
- items?: SalesContextType["items"];
- paymentMethodId?: string;
- }): number => {
- const { items: itemz = items, paymentMethodId } = options || {};
-
- if (paymentMethodId && paymentMethods?.content) {
- // Find the payment method ID that matches the requested payment method form
- if (overriddenCohortPriceLevel === undefined) {
- return (
- paymentMethodIdToCartTotal[paymentMethodId] ??
- transactionTotalPrice()
- );
- }
- }
+ (itemz = items) => {
if (!itemz) return 0;
let price = 0;
for (const [, lineItem] of itemz) {
@@ -567,55 +444,12 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
}
return round(price, 2);
},
- [
- items,
- paymentMethodIdToCartTotal,
- paymentMethods?.content,
- overriddenCohortPriceLevel,
- ],
- );
-
- // Helper function to find the best payment method (default if available, otherwise cheapest)
- const findBestPaymentMethod = useCallback(
- (
- paymentMethods: EntitySalesChannelPaymentMethod[] | undefined,
- defaultPaymentMethodId?: string,
- ) => {
- if (!paymentMethods || paymentMethods.length === 0) return null;
-
- // First, try to find the default payment method
- const defaultMethod = paymentMethods.find(
- (pm) => pm.id === defaultPaymentMethodId,
- );
- if (defaultMethod) {
- return defaultMethod;
- }
-
- // If no default found, find the cheapest one
- let cheapestMethod = paymentMethods[0];
- let cheapestPrice = transactionTotalPrice({
- paymentMethodId: cheapestMethod?.id,
- });
-
- for (const method of paymentMethods) {
- const price = transactionTotalPrice({ paymentMethodId: method.id });
- if (price < cheapestPrice) {
- cheapestPrice = price;
- cheapestMethod = method;
- }
- }
-
- return cheapestMethod || null;
- },
- [transactionTotalPrice],
+ [items],
);
const setItemsInCart = useCallback(
- async (
- it: Map<number, LineItem>,
- paymentMethodIdToCartTotal: Record<string, number> = {},
- ) => {
- if (!register.isRegisterOpen || skipSetItemsInCartRef.current) return;
+ async (it: Map<number, LineItem>) => {
+ if (!register.isRegisterOpen) return;
if (deviceBusy) return;
if (it.size === 0) {
try {
@@ -642,6 +476,8 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
cartDisplayAbortController.current = new AbortController();
}
+ const signal = cartDisplayAbortController.current.signal;
+
const cartItems = [...it.values()].map((lineItem) => {
const cartItem: TransactionCartItem = {
...lineItem,
@@ -653,62 +489,21 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
return cartItem;
});
- const defaultPaymentMethodId =
- selectedSalesChannel?.defaultPaymentMethodId;
- const calculatedPaymentMethodTotals = Object.entries(
- paymentMethodTypeToPaymentMethod,
- ).reduce(
- (acc, [paymentForm, paymentMethods]) => {
- if (paymentMethods && paymentMethods.length > 0) {
- // First filter for displayOnPayButton=true, then find the best method
- const displayableMethods = paymentMethods.filter(
- (method) => method.displayOnPayButton,
- );
- const bestMethod = findBestPaymentMethod(
- displayableMethods,
- defaultPaymentMethodId,
- );
- if (bestMethod) {
- acc[paymentForm] =
- paymentMethodIdToCartTotal[bestMethod.id] ||
- transactionTotalPrice({ paymentMethodId: bestMethod.id });
- }
- }
- return acc;
- },
- {} as Record<string, number>,
- );
-
const s = async () => {
return await setItemsInCartMutate({
items: cartItems,
- paymentMethodTotals: overriddenCohortPriceLevel
- ? {}
- : calculatedPaymentMethodTotals,
});
};
try {
await s();
- } catch {
+ } catch (err) {
// retry once on failure
setTimeout(() => {
s().catch(() => undefined);
}, 300);
}
},
- [
- deviceBusy,
- entity.id,
- register.isRegisterOpen,
- register.registerNumber,
- emptyCart,
- setItemsInCartMutate,
- transactionTotalPrice,
- paymentMethodTypeToPaymentMethod,
- findBestPaymentMethod,
- selectedSalesChannel?.defaultPaymentMethodId,
- overriddenCohortPriceLevel,
- ],
+ [deviceBusy, entity.id, register.isRegisterOpen, register.registerNumber],
);
useBeforeUnload(() => {
@@ -725,174 +520,14 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
useEffect(() => {
if (!window.location.href.includes("sale")) return;
- void setItemsInCart(debouncedItems ?? new Map(), debouncedTotals);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [debouncedItems, debouncedTotals]);
-
- const calculateBackgroundPaymentMethodTotals = useCallback(
- async (opts: PricingRequestOptions) => {
- if (
- overriddenCohortPriceLevel !== undefined ||
- !hasMultiplePriceLevelsOnSalesChannel
- ) {
- setPaymentMethodIdToCartTotal({});
- return;
- }
-
- const {
- requestedDiscount,
- requestedCustomer,
- requestTaxExempt,
- requestedItems,
- paymentMethodId,
- } = opts;
- console.log(
- "calculateBackgroundPaymentMethodTotals paymentMethodId",
- paymentMethodId,
- );
- if (paymentMethodId !== undefined) {
- return;
- }
- if (!requestedItems) throw new Error("Requested items are required");
- if (requestedItems.size === 0) {
- setPaymentMethodIdToCartTotal({});
- return;
- }
-
- // Abort any previous background calculation requests
- if (!backgroundCalculationAbortController.current) {
- backgroundCalculationAbortController.current = new AbortController();
- console.log("backgroundCalculationAbortController created");
- } else {
- try {
- backgroundCalculationAbortController.current.abort();
- console.log("backgroundCalculationAbortController aborted");
- } catch (e) {
- console.warn(e);
- }
- backgroundCalculationAbortController.current = new AbortController();
- console.log("backgroundCalculationAbortController created");
- }
-
- const signal = backgroundCalculationAbortController.current.signal;
- console.log("backgroundCalculationAbortController signal", signal);
- setIsCalculatingBackgroundPaymentMethodTotals(true);
- console.log("setIsCalculatingBackgroundPaymentMethodTotals true");
- try {
- const nonDefaultPaymentMethods =
- paymentMethods?.content?.filter(
- (pm) => pm.id !== selectedSalesChannel.defaultPaymentMethodId,
- ) ?? [];
-
- const paymentMethodIdToCartTotal: Record<string, number> = {};
- const cachedTotalz: Record<number, number> = {};
- console.log("nonDefaultPaymentMethods", nonDefaultPaymentMethods);
- for (const paymentMethod of nonDefaultPaymentMethods) {
- const cachedTotal = cachedTotalz[paymentMethod.cohortPriceLevelId];
- if (cachedTotal) {
- paymentMethodIdToCartTotal[paymentMethod.id] = cachedTotal;
- continue;
- }
- const pricingCartInputItems: PricingCartInputItem[] = [];
- for (const lineItem of requestedItems.values()) {
- if (lineItem.item?.ei_id === undefined) {
- const unknownItem: UnknownItem = {
- upc: lineItem.upcCode,
- name: lineItem.name,
- price: lineItem.price,
- bottleDepositMultiplier: lineItem.bottleFeeMultiplier ?? 0,
- envFeeMultiplier: lineItem.environmentFeeMultiplier ?? 0,
- department: departmentKeyMap?.get(lineItem.department)?.id!,
- };
- pricingCartInputItems.push({
- type: PricingCartInputItemType.unknownItem,
- unknownItem: unknownItem,
- transactionItemId: lineItem.id,
- quantity: lineItem.quantity,
- taxExempt: false,
- });
- } else {
- pricingCartInputItems.push(
- convertToPricingCartInputItem({
- ...lineItem,
- }),
- );
- }
- }
-
- const res = await getCartPricingRequest(
- {
- items: pricingCartInputItems,
- transactionId: transactionId ?? 0,
- discount: requestedDiscount,
- governmentID: governmentID,
- loyaltyCustomerId: requestedCustomer?.loyaltyCustomerId,
- taxExempt: requestTaxExempt,
- persistToTransaction: false,
- salesChannelId: selectedSalesChannel.id,
- overriddenPriceLevel: paymentMethod.cohortPriceLevelId,
- },
- { signal },
- );
- console.log(
- "getCartPricingRequest res",
- res,
- " for paymentMethod",
- paymentMethod,
- );
- // Check if we've been aborted before making the API call
- if (signal.aborted) {
- throw new CanceledError("Background calculation was canceled");
- }
- const total = res.reduce((acc, item) => acc + item.total, 0);
- paymentMethodIdToCartTotal[paymentMethod.id] = total;
- cachedTotalz[paymentMethod.cohortPriceLevelId] = total;
- }
-
- console.log("paymentMethodIdToCartTotal", paymentMethodIdToCartTotal);
- setPaymentMethodIdToCartTotal(paymentMethodIdToCartTotal);
- } catch (err) {
- if (err instanceof CanceledError) {
- console.warn("Background calculation was canceled");
- return;
- }
- captureException(err);
- setPaymentMethodIdToCartTotal({});
- throw err;
- } finally {
- setIsCalculatingBackgroundPaymentMethodTotals(false);
- console.log("setIsCalculatingBackgroundPaymentMethodTotals false");
- }
- },
- [
- overriddenCohortPriceLevel,
- paymentMethods,
- governmentID,
- selectedSalesChannel.id,
- selectedSalesChannel.defaultPaymentMethodId,
- transactionId,
- hasMultiplePriceLevelsOnSalesChannel,
- departmentKeyMap,
- ],
- );
+ void setItemsInCart(debouncedItems ?? new Map());
+ }, [debouncedItems, setItemsInCart]);
const urgentCalculateCartPrice = useCallback(
async (opts: PricingRequestOptions) => {
if (cartPriceCallInProgress.current) return;
- let {
- requestedDiscount,
- requestTaxExempt,
- requestedCustomer,
- paymentMethodId,
- overriddenPriceLevel,
- hasOverriddenPriceLevel,
- } = opts;
-
- console.log(
- "calculateCartPriceQueue length",
- calculateCartPriceQueue.length,
- );
+ let { requestedDiscount, requestTaxExempt, requestedCustomer } = opts;
// Get the latest item details. The previous ones are stale.
const itemDetailz = calculateCartPriceQueue.pop();
@@ -936,7 +571,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
id: draftedTransactionItemId,
};
- if (finalItem.item?.ei_variable_cost_percent) {
+ if (!!finalItem.item?.variableCostPct) {
setAddingVariableCostItemId(finalItem.id);
}
itemDetailz.set(draftedTransactionItemId, finalItem);
@@ -959,7 +594,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const signal = cartPricingAbortController.current.signal;
for (const lineItem of itemDetailz.values()) {
- if (lineItem.item?.ei_id === undefined) {
+ if (lineItem.item?.id === undefined) {
const unknownItem: UnknownItem = {
upc: lineItem.upcCode,
name: lineItem.name,
@@ -987,18 +622,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const getCartPricing = async () => {
try {
let newCalculationWarning = false;
-
- let requestedOverriddenPriceLevel = (() => {
- if (hasOverriddenPriceLevel) {
- return overriddenPriceLevel;
- }
- return undefined;
- })();
- if (!requestedOverriddenPriceLevel) {
- requestedOverriddenPriceLevel = paymentMethods?.content?.find(
- (pm) => pm.id === paymentMethodId,
- )?.cohortPriceLevelId;
- }
const response = await getCartPricingRequest(
{
items: pricingCartInputItems,
@@ -1008,29 +631,15 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
loyaltyCustomerId: requestedCustomer?.loyaltyCustomerId,
salesChannelId: selectedSalesChannel.id,
taxExempt: requestTaxExempt,
- overriddenPriceLevel: requestedOverriddenPriceLevel,
},
{ signal },
);
setIsGetCartPricingError(false);
- const newItemDetailsArray = await Promise.all(
- response.map(async (i: PricingCartOutputItem) => {
+ const newItemDetails = new Map(
+ response.map((i: PricingCartOutputItem) => {
const prevLineItem = i.transactionItemId
? itemDetailz.get(i.transactionItemId)
: undefined;
-
- const options = RetrieveItemsByUpcQuery(
- entity.id,
- null,
- i.entityItem?.id ? [i.entityItem.id] : [],
- );
- const eRes = i.entityItem
- ? await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
- )
- : undefined;
-
const lineItem: LineItem = {
...i,
upcCode: i.upc,
@@ -1038,7 +647,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
tax: i.tax,
taxRate: i.taxRate,
calculationMetadata: i.calculationMetadata,
- taxExempt: i.taxExempt ?? false,
+ taxExempt: false,
totalPrice: i.total,
promotionItems: i.promotionAmounts,
discount: i.discount ?? 0,
@@ -1047,13 +656,12 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
lineItemDiscount: prevLineItem?.lineItemDiscount,
bottleFee: i.bottleDeposit,
environmentFee: i.environmentFee,
- item: eRes?.rows?.[0],
+ item: i.entityItem,
itemId: i.entityItem?.id as number,
transactionId: transactionId,
department: i.department.id,
id: i.transactionItemId,
};
-
if (
prevLineItem &&
!hasCalculationWarning(prevLineItem) &&
@@ -1061,11 +669,9 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
) {
newCalculationWarning = true;
}
-
- return [lineItem.id, lineItem] as const;
+ return [lineItem.id, lineItem];
}),
);
- const newItemDetails = new Map(newItemDetailsArray);
// Show warning if any of the items have a warning
if (newCalculationWarning && calculateCartPriceQueue.length === 0) {
@@ -1092,19 +698,9 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
setCustomerState(requestedCustomer);
setCartDiscount(requestedDiscount);
setTaxExempt(requestTaxExempt);
- if (paymentMethodId === undefined) {
- // no override passed in directly
- void calculateBackgroundPaymentMethodTotalsRef.current({
- requestedItems: newItemDetails,
- requestTaxExempt: requestTaxExempt,
- requestedCustomer: requestedCustomer,
- requestedDiscount: requestedDiscount,
- });
- }
return newItemDetails;
}
calculateCartPriceQueue.push(newItemDetails);
-
throw new Error(cartPricingQueueNotEmptyMessage);
} catch (err) {
if (err instanceof CanceledError) {
@@ -1170,28 +766,18 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
});
},
[
- entity.id,
+ entity?.id,
departmentMap,
departmentKeyMap,
transactionId,
draftTransactionItem,
governmentID,
selectedSalesChannel.id,
- db,
toast,
- paymentMethods,
],
);
const urgentCalculateCartPriceRef = useRef(urgentCalculateCartPrice);
- const calculateBackgroundPaymentMethodTotalsRef = useRef(
- calculateBackgroundPaymentMethodTotals,
- );
- useEffect(() => {
- calculateBackgroundPaymentMethodTotalsRef.current =
- calculateBackgroundPaymentMethodTotals;
- }, [calculateBackgroundPaymentMethodTotals]);
-
useEffect(() => {
urgentCalculateCartPriceRef.current = urgentCalculateCartPrice;
}, [urgentCalculateCartPrice]);
@@ -1205,7 +791,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
calculateCartPriceQueue.push(itemz);
setIsCalculatingCartPrice(true);
const output = await urgentCalculateCartPriceRef.current(opts);
-
setIsCalculatingCartPrice(false);
if (output === undefined) {
throw new Error("Cart price calculation failed");
@@ -1217,21 +802,18 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
const isPriceAtCost = customer?.priceAtCost ?? false;
- const isEntityItemDetail = useCallback(
- (
- itemDetailz:
- | RetrieveItemsByUpc
- | Omit<DraftTransactionItemInput, "transactionId">,
- ): itemDetailz is RetrieveItemsByUpc => {
- return "ei_id" in itemDetailz;
- },
- [],
- );
+ const isEntityItemDetail = (
+ itemDetailz:
+ | EntityItemDetail
+ | Omit<DraftTransactionItemInput, "transactionId">,
+ ): itemDetailz is EntityItemDetail => {
+ return "cohortItem" in itemDetailz;
+ };
const addSingleItemToCart = useCallback(
async (
itemDetailz:
- | RetrieveItemsByUpc
+ | EntityItemDetail
| Omit<DraftTransactionItemInput, "transactionId">,
quantity = 1,
) => {
@@ -1300,7 +882,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
},
[
transactionId,
- isEntityItemDetail,
taxExempt,
isPriceAtCost,
calculateCartPrice,
@@ -1317,7 +898,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
}, [items, lineItemDiscounts]);
const handleRetrievedItems = useCallback(
- async (items: RetrieveItemsByUpc[], quantity: number = 1) => {
+ async (items: EntityItemDetail[], quantity: number = 1) => {
try {
if (items.length === 1) {
const item = items[0];
@@ -1340,59 +921,29 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
console.error(err);
}
},
- [addSingleItemToCart],
+ [addSingleItemToCart, setMultipleChoices],
);
const retrieveItemsLikeUpc = useCallback(
async (barCode: string, exact = false, quantity = 1) => {
+ // AbortController setup
+ // https://chat.openai.com/share/c9dca7d2-cef9-4cef-a47a-8cc30613ba63
+
+ const signal = retrieveUpcAbortController.current.signal;
+
setQuantity(1);
try {
- const startTime = performance.now();
- const options = RetrieveItemsByUpcQuery(
- entity.id,
- exact ? barCode : `%${barCode}%`,
- null,
- );
- console.log("options", options.query, options.params);
- const eRes = await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
- );
- const opt = retrieveItemsLikeUpcQueryOptions({
- entityId: entity.id,
- upcCode: exact ? barCode : `%${barCode}%`,
- });
- queryClient
- .fetchQuery(opt)
- .then((res) => {
- // if res != eRes, log to posthog
- // this is to track any discrepancies between pg-lite and spring backend
- // we can remove this after a few weeks of logging
- if (
- !isEqual(
- res.map((r) => r.id).toSorted((a, b) => a - b),
- eRes.rows.map((r) => r.ei_id).toSorted((a, b) => a - b),
- )
- ) {
- posthog.capture("pg_lite_spring_backend_discrepancy", {
- entityId: entity.id,
- upcCode: exact ? barCode : `%${barCode}%`,
- pgLiteCount: eRes.rows.length,
- springBackendCount: res.length,
- pgLiteItems: eRes.rows,
- springBackendItems: res,
- });
- }
- })
- .catch((err) => {
- captureException(err);
- });
- const endTime = performance.now();
- console.log(
- `Retrieved ${JSON.stringify(eRes)} electric items in ${endTime - startTime}ms`,
+ const retrieveItemUpcOptions = retrieveItemsLikeUpcQueryOptions(
+ {
+ upcCode: exact ? barCode : `%${barCode}%`,
+ entityId: entity.id,
+ },
+ {
+ signal: signal,
+ },
);
-
- await handleRetrievedItems(eRes.rows, quantity);
+ const res = await queryClient.fetchQuery(retrieveItemUpcOptions);
+ await handleRetrievedItems(res, quantity);
} catch (err: any) {
if (err instanceof CanceledError) {
console.warn(err);
@@ -1402,7 +953,7 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
console.error(err.message);
}
},
- [entity.id, db, queryClient, handleRetrievedItems],
+ [queryClient, entity.id, handleRetrievedItems],
);
const calculateCartPriceRef = useRef(calculateCartPrice);
@@ -1419,18 +970,21 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
setCustomerState(undefined);
setCartDiscount(undefined);
setIsGetCartPricingError(false);
- setIsCalculatingBackgroundPaymentMethodTotals(false);
- setPaymentMethodIdToCartTotal({});
lastPricingRequestId.current = null;
retrieveUpcAbortController.current.abort();
retrieveUpcAbortController.current = new AbortController();
cartDisplayAbortController.current?.abort();
cartDisplayAbortController.current = new AbortController();
cartPriceCallInProgress.current = false;
- backgroundCalculationAbortController.current?.abort();
- backgroundCalculationAbortController.current = new AbortController();
setSelectedItems(new Map());
- }, [resetSalesChannel]);
+ }, [
+ resetSalesChannel,
+ setItems,
+ setTaxExempt,
+ setGovernmentID,
+ setCartDiscount,
+ setSelectedItems,
+ ]);
const setAndDraftGovernmentID = useCallback(
async (id?: GovernmentId) => {
@@ -1452,24 +1006,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
[toast],
);
- // Helper function to calculate methods with prices
- const calculateMethodsWithPrices = useCallback(
- (paymentForm: TransactionPaymentForm) => {
- const paymentMethods =
- paymentMethodTypeToPaymentMethod[paymentForm] || [];
-
- const seenPrices = new Set<number>();
- return paymentMethods
- .filter((paymentMethod) => paymentMethod != null)
- .map((paymentMethod) => ({
- method: paymentMethod,
- total: transactionTotalPrice({ paymentMethodId: paymentMethod.id }),
- }))
- .filter(({ total }) => total !== undefined && total > 0);
- },
- [paymentMethodTypeToPaymentMethod, transactionTotalPrice],
- );
-
if (!register.isRegisterOpen) {
return <Navigate to={"/register/open/"} replace />;
}
@@ -1497,9 +1033,8 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
handleRetrievedItems,
retrieveItemsLikeUpc,
setItemsInCart,
- resetCartToCurrentItems: async () => {
- await setItemsInCart(debouncedItems ?? new Map(), debouncedTotals);
- },
+ resetCartToCurrentItems: () =>
+ setItemsInCart(debouncedItems ?? new Map()),
clearCart,
multipleChoices,
setMultipleChoices,
@@ -1512,12 +1047,6 @@ export const SalesContextProvider: React.FC<SalesContextProviderProps> = ({
draftTransaction,
isCalculatingCartPrice,
isGetCartPricingError,
- paymentMethodTypeToPaymentMethod: paymentMethodTypeToPaymentMethod,
- isCalculatingBackgroundPaymentMethodTotals,
- hasMultiplePriceLevelsOnSalesChannel,
- calculateMethodsWithPrices,
- findBestPaymentMethod,
- setSkipSetItemsInCart,
}}
>
{children}
diff --git a/src/context/Sales/SalesPaymentContext.tsx b/src/context/Sales/SalesPaymentContext.tsx
index d4a99e37..76a75b6d 100644
--- a/src/context/Sales/SalesPaymentContext.tsx
+++ b/src/context/Sales/SalesPaymentContext.tsx
@@ -37,10 +37,7 @@ import {
usePayLaterTransaction,
useProcessTransactionSale,
} from "src/generated";
-import {
- EntitySalesChannel,
- EntitySalesChannelPaymentMethod,
-} from "src/spring-generated";
+import { EntitySalesChannel } from "src/spring-generated";
import { useSessionStorage } from "usehooks-ts";
import useCashDrawer from "../../components/CashDrawer";
import { CreditSaleModalV2 } from "../../components/SalesScreenComponents/Modals/CreditCardSaleModalV2";
@@ -66,7 +63,6 @@ export type AmountReceived = {
giftCardAmountReceived?: number;
pointsAmountReceived?: number;
paymentForm: TransactionPaymentForm;
- paymentMethodId?: string;
giftCardId?: string;
creditCardId?: string;
salesChannel?: TransactionSalesChannel;
@@ -97,14 +93,8 @@ export interface SalesPaymentContextType {
setGovernmentID: (
id: SalesPaymentContextType["governmentID"],
) => void | Promise<void>;
- transactionTotalPrice: (options?: {
- items?: SalesContextType["items"];
- paymentMethodId?: string;
- }) => number;
- creditCardPaid: (
- confirmationNeeded?: boolean,
- paymentMethodId?: string,
- ) => void;
+ transactionTotalPrice: (itemz?: SalesContextType["items"]) => number;
+ creditCardPaid: (confirmationNeeded?: boolean) => void;
amountReceived?: AmountReceived;
setAmountPaid: Dispatch<SetStateAction<AmountReceived | undefined>>;
lastReceiptId?: number;
@@ -122,29 +112,9 @@ export interface SalesPaymentContextType {
salesChannel: EntitySalesChannel;
isProcessSaleRequested: boolean;
isCalculatingCartPrice?: boolean;
- isGetCartPricingError?: boolean;
salePaymentType: SalePaymentType;
creditCardPaidPending: boolean;
reviewTransactionModalPending: boolean;
- calculateCartPrice?: (() => Promise<SalesContextType["items"]>) | undefined;
- selectedCashPaymentMethodId?: string;
- setSelectedCashPaymentMethodId: React.Dispatch<
- React.SetStateAction<string | undefined>
- >;
- // Payment method functions (passed through from SalesContext)
- paymentMethodTypeToPaymentMethod: Record<
- string,
- Array<EntitySalesChannelPaymentMethod>
- >;
- calculateMethodsWithPrices: (
- paymentForm: TransactionPaymentForm,
- ) => Array<{ method: EntitySalesChannelPaymentMethod; total: number }>;
- findBestPaymentMethod: (
- paymentMethods: EntitySalesChannelPaymentMethod[] | undefined,
- defaultPaymentMethodId?: string,
- ) => EntitySalesChannelPaymentMethod | null;
- isCalculatingBackgroundPaymentMethodTotals: boolean;
- selectedSalesChannel?: EntitySalesChannel; // From SalesContext/SalePageConfig
}
export const SalesPaymentContext = createContext<
@@ -167,11 +137,8 @@ export interface SalesPaymentProviderProps {
setTransactionId: (
transactionId?: TransactionId,
) => Promise<DraftTransactionMutationResponse | undefined>;
- transactionTotalPrice: (options?: {
- items?: SalesContextType["items"];
- paymentMethodId?: string;
- }) => number;
- resetCartToCurrentItems: () => Promise<void> | void;
+ transactionTotalPrice: () => number;
+ resetCartToCurrentItems: () => void;
clearCart: () => void | Promise<void>;
governmentID?: GovernmentId;
setGovernmentID: (
@@ -179,31 +146,12 @@ export interface SalesPaymentProviderProps {
) => void | Promise<void>;
customer?: LoyaltyCustomer;
salesChannel: EntitySalesChannel;
- overriddenCohortPriceLevel?: number;
reviewTransactionModal?: UseDisclosureReturn;
isCalculatingCartPrice?: boolean;
payAfterConfirm: boolean;
salePaymentType: SalePaymentType;
isGetCartPricingError?: boolean;
baseAmountReceived?: AmountReceived;
- calculateCartPrice?: (
- paymentMethodId?: string,
- ) => Promise<SalesContextType["items"]>;
- // Payment method functions (passed through from SalesContext)
- paymentMethodTypeToPaymentMethod: Record<
- string,
- Array<EntitySalesChannelPaymentMethod>
- >;
- calculateMethodsWithPrices: (
- paymentForm: TransactionPaymentForm,
- ) => Array<{ method: EntitySalesChannelPaymentMethod; total: number }>;
- findBestPaymentMethod: (
- paymentMethods: EntitySalesChannelPaymentMethod[] | undefined,
- defaultPaymentMethodId?: string,
- ) => EntitySalesChannelPaymentMethod | null;
- isCalculatingBackgroundPaymentMethodTotals: boolean;
- selectedSalesChannel?: EntitySalesChannel; // From SalesContext/SalePageConfig
- setSkipSetItemsInCart: (skip: boolean) => void;
}
export const SalesPaymentProvider = (
@@ -211,7 +159,6 @@ export const SalesPaymentProvider = (
) => {
const {
salesChannel,
- overriddenCohortPriceLevel,
transactionTotalPrice,
transactionItems,
clearCart,
@@ -226,19 +173,11 @@ export const SalesPaymentProvider = (
isCalculatingCartPrice,
isGetCartPricingError,
baseAmountReceived,
- calculateCartPrice,
- paymentMethodTypeToPaymentMethod,
- calculateMethodsWithPrices,
- findBestPaymentMethod,
- isCalculatingBackgroundPaymentMethodTotals,
- selectedSalesChannel,
- setSkipSetItemsInCart,
} = props;
// APIs
const [isProcessSaleRequested, setIsProcessSaleRequested] = useState(false);
- const [selectedCashPaymentMethodId, setSelectedCashPaymentMethodId] =
- useState<string | undefined>();
+
const { mutateAsync: draftTransactionPayment } = useDraftTransactionPayment();
const { mutateAsync: processTransactionSale } = useProcessTransactionSale({
mutation: {
@@ -313,16 +252,7 @@ export const SalesPaymentProvider = (
[_setAmountPaid, baseAmountReceived],
);
- const [isPersisting, _setIsPersisting] = useState(false);
-
- const setIsPersisting = useCallback(
- (isPersisting: boolean) => {
- _setIsPersisting(isPersisting);
- setSkipSetItemsInCart(isPersisting);
- },
- [_setIsPersisting, setSkipSetItemsInCart],
- );
-
+ const [isPersisting, setIsPersisting] = useState(false);
const [lastReceiptId, setLastReceiptId] = useSessionStorage<
number | undefined
>("lastReceiptId", undefined);
@@ -402,11 +332,8 @@ export const SalesPaymentProvider = (
onlineAmountReceived +
pointsAmountReceived +
doordashAmountReceived;
- const totalPrice = transactionTotalPrice({
- paymentMethodId: amountReceived?.paymentMethodId,
- });
- if (amountTendered >= totalPrice) {
- return amountTendered - totalPrice;
+ if (amountTendered >= transactionTotalPrice()) {
+ return amountTendered - transactionTotalPrice();
}
return 0;
},
@@ -518,12 +445,8 @@ export const SalesPaymentProvider = (
reviewTransactionModalOnClose();
creditCardModalV2OnClose();
void onSettledTransactionRef.current();
- await resetCartToCurrentItems();
- if (calculateCartPrice) {
- await calculateCartPrice();
- }
+ resetCartToCurrentItems();
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
creditCardModalV2OnClose,
resetCartToCurrentItems,
@@ -544,7 +467,6 @@ export const SalesPaymentProvider = (
});
setAmountPaid(undefined);
setIsPersisting(false);
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryClient]);
const onSettledTransactionRef = useRef(onSettledTransaction);
@@ -574,12 +496,7 @@ export const SalesPaymentProvider = (
if (!register.isRegisterOpen) return;
if (isPersisting) return;
- const transactionTotalPriceCalled = round(
- transactionTotalPrice({
- paymentMethodId: amountReceived?.paymentMethodId,
- }),
- 2,
- );
+ const transactionTotalPriceCalled = round(transactionTotalPrice(), 2);
const summedAmountPaid = round(
amountPaid +
creditCardAmountReceived +
@@ -622,10 +539,6 @@ export const SalesPaymentProvider = (
);
try {
setIsPersisting(true);
- if (calculateCartPrice && overriddenCohortPriceLevel === undefined) {
- await calculateCartPrice(amountReceived?.paymentMethodId);
- }
-
await draftTransactionPayment({
transactionId: transactionIdCur,
registerNumber: register.registerNumber,
@@ -748,13 +661,11 @@ export const SalesPaymentProvider = (
setIsPersisting(false);
setIsProcessSaleRequested(false);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
amountReceived,
register.isRegisterOpen,
register.registerNumber,
isPersisting,
- setIsPersisting,
transactionTotalPrice,
draftTransactionPayment,
payLaterTransaction,
@@ -780,22 +691,15 @@ export const SalesPaymentProvider = (
persistTransactionRef.current = persistTransaction;
}, [persistTransaction]);
- const _creditCardPaid = useCallback(
- (confirmationNeeded?: boolean, paymentMethodId?: string) => {
- setAmountPaid({
- amountPaid: 0,
- creditCardAmountReceived: transactionTotalPrice({
- paymentMethodId,
- }),
- paymentForm: TransactionPaymentForm["CREDIT CARD"],
- paymentMethodId,
- });
+ const _creditCardPaid = useCallback(() => {
+ setAmountPaid({
+ amountPaid: 0,
+ creditCardAmountReceived: transactionTotalPrice(),
+ paymentForm: TransactionPaymentForm["CREDIT CARD"],
+ });
- reviewTransactionModalOnOpen();
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [transactionTotalPrice, reviewTransactionModalOnOpen],
- );
+ reviewTransactionModalOnOpen();
+ }, [transactionTotalPrice, reviewTransactionModalOnOpen]);
const {
trigger: creditCardPaid,
@@ -814,7 +718,6 @@ export const SalesPaymentProvider = (
if (transactionItems.length === 0) {
setAmountPaid(undefined);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [transactionItems]);
useEffect(() => {
@@ -854,14 +757,6 @@ export const SalesPaymentProvider = (
persistPending,
creditCardPaidPending,
reviewTransactionModalPending,
- calculateCartPrice,
- selectedCashPaymentMethodId,
- setSelectedCashPaymentMethodId,
- paymentMethodTypeToPaymentMethod,
- calculateMethodsWithPrices,
- findBestPaymentMethod,
- isCalculatingBackgroundPaymentMethodTotals,
- selectedSalesChannel,
}}
>
<>
@@ -870,7 +765,6 @@ export const SalesPaymentProvider = (
isOpen={payWithCashModal.isOpen}
onClose={payWithCashModal.onClose}
openChangeDueModal={reviewTransactionModal.onOpen}
- selectedCashPaymentMethodId={selectedCashPaymentMethodId}
/>
<ReviewSaleModal
{...reviewTransactionModal}
diff --git a/src/context/StorefrontContext/StorefrontContext.tsx b/src/context/StorefrontContext/StorefrontContext.tsx
deleted file mode 100644
index e09a94ee..00000000
--- a/src/context/StorefrontContext/StorefrontContext.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createContext } from "react";
-
-export interface StorefrontContext {}
-
-export const StorefrontContext = createContext<StorefrontContext | undefined>(
- undefined,
-);
diff --git a/src/context/StorefrontContext/StorefrontProvider.tsx b/src/context/StorefrontContext/StorefrontProvider.tsx
deleted file mode 100644
index 7608245c..00000000
--- a/src/context/StorefrontContext/StorefrontProvider.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import { Button } from "components/ui/button";
-import { toast } from "components/ui/use-toast";
-import { captureException } from "config/sentry/TransformitySentry";
-import { useStorefrontDecisionHandler } from "hooks/useStorefrontDecisionHandler";
-import { ShoppingCart } from "lucide-react";
-import { useCallback, useEffect, useRef } from "react";
-import {
- getTransactionByTransactionItem,
- WebsocketBroadcastMessagePayload,
-} from "src/phoenix-generated";
-import { playNotificationSound } from "../../utils/audioUtils";
-import { StorefrontContext } from "./StorefrontContext";
-
-export interface StorefrontProviderProps {
- children: React.ReactNode;
-}
-
-export const StorefrontProvider: React.FC<StorefrontProviderProps> = ({
- children,
-}) => {
- const notifiedTransactions = useRef(new Map<string, () => void>());
- const cleanupTimeouts = useRef(new Map<string, NodeJS.Timeout>());
- const onOrderItemDecision = useCallback(
- async (event: WebsocketBroadcastMessagePayload) => {
- if (!event.orderItemDecision) {
- return;
- }
- const transaction = await getTransactionByTransactionItem(
- event.orderItemDecision.transaction_item_id,
- ).catch((err) => {
- captureException(err);
- return null;
- });
- if (!transaction) {
- return;
- }
-
- const transactionId = transaction.id.toString();
-
- // Play notification sound only if we haven't already notified for this transaction
- if (
- event.orderItemDecision.status === "CREATED" &&
- !notifiedTransactions.current.has(transactionId)
- ) {
- void playNotificationSound();
- const { dismiss } = toast({
- id: transactionId,
- duration: Infinity,
- className: "bg-blue-600 text-white border-blue-500",
- title: "New Online Order",
- description: (
- <div className="flex items-start gap-3 mt-1">
- <ShoppingCart className="h-5 w-5 text-white mt-0.5" />
- <div className="flex flex-col gap-1">
- <p>
- Order ID:{" "}
- <span className="font-mono font-medium">
- {transaction.id}
- </span>
- </p>
- <p className="text-blue-100">
- Order Date:{" "}
- {transaction.paidAt
- ? new Date(transaction.paidAt).toLocaleString()
- : "N/A"}
- </p>
- </div>
- </div>
- ),
- action: (
- <Button
- variant="outline"
- className="border-white text-white hover:bg-white/10"
- asChild
- >
- <a href={`/transaction/${transaction.id}`}>View Order</a>
- </Button>
- ),
- });
- notifiedTransactions.current.set(transactionId, dismiss);
-
- // Set up cleanup to remove the transaction ID after 5 minutes
- const timeoutId = setTimeout(() => {
- notifiedTransactions.current.delete(transactionId);
- cleanupTimeouts.current.delete(transactionId);
- }, 300000);
-
- cleanupTimeouts.current.set(transactionId, timeoutId);
- } else if (
- ["ACCEPTED", "REJECTED"].includes(event.orderItemDecision.status)
- ) {
- notifiedTransactions.current.get(transactionId)?.();
- notifiedTransactions.current.delete(transactionId);
- cleanupTimeouts.current.delete(transactionId);
- }
- },
- [],
- );
-
- // TODO: enabled only if storefront exists
- useStorefrontDecisionHandler(true, onOrderItemDecision);
-
- // Cleanup timeouts on unmount
- useEffect(() => {
- const currentCleanupTimeouts = cleanupTimeouts.current;
- const currentNotifiedTransactions = notifiedTransactions.current;
- return () => {
- // Clear all pending timeouts when component unmounts
- currentCleanupTimeouts.forEach((timeoutId) => {
- clearTimeout(timeoutId);
- });
- currentCleanupTimeouts.clear();
- currentNotifiedTransactions.clear();
- };
- }, []);
-
- return (
- <StorefrontContext.Provider value={{}}>
- {children}
- </StorefrontContext.Provider>
- );
-};
diff --git a/src/context/WebsocketContext/WebsocketContext.tsx b/src/context/WebsocketContext/WebsocketContext.tsx
deleted file mode 100644
index 55be98b1..00000000
--- a/src/context/WebsocketContext/WebsocketContext.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { createContext } from "react";
-import { ReadyState } from "react-use-websocket";
-import {
- WebsocketBroadcastMessagePayload,
- WebsocketWebsocketMessageType,
-} from "src/phoenix-generated";
-
-export type EventTypeMap = {
- [WebsocketWebsocketMessageType.ConnectionInfoRequest]: {
- type: WebsocketWebsocketMessageType.ConnectionInfoRequest;
- };
- [WebsocketWebsocketMessageType.ConnectionInfoResponse]: WebsocketBroadcastMessagePayload["connectionInfo"];
- [WebsocketWebsocketMessageType.OrderItemDecision]: WebsocketBroadcastMessagePayload["orderItemDecision"];
- [WebsocketWebsocketMessageType.PING]: {
- type: WebsocketWebsocketMessageType.PING;
- };
- [WebsocketWebsocketMessageType.PONG]: {
- type: WebsocketWebsocketMessageType.PONG;
- };
-};
-export type EventType = keyof EventTypeMap;
-export type EventPayload<T extends EventType> = EventTypeMap[T] & { type: T };
-
-export type WebsocketContext = {
- readyState: ReadyState;
- subscribe: <T extends EventType>(
- eventType: T,
- callback: (payload: WebsocketBroadcastMessagePayload) => void,
- ) => void;
- unsubscribe: <T extends EventType>(
- eventType: T,
- callback: (payload: WebsocketBroadcastMessagePayload) => void,
- ) => void;
- sendMessage: <T extends EventType>(payload: EventPayload<T>) => void;
- emit: <T extends EventType>(eventType: T, payload: EventPayload<T>) => void;
- connectionId: string | null;
-};
-
-export const WebsocketContext = createContext<WebsocketContext | undefined>(
- undefined,
-);
diff --git a/src/context/WebsocketContext/WebsocketProvider.tsx b/src/context/WebsocketContext/WebsocketProvider.tsx
deleted file mode 100644
index 2508b652..00000000
--- a/src/context/WebsocketContext/WebsocketProvider.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import { captureException } from "config/sentry/TransformitySentry";
-import { useCallback, useEffect, useRef, useState } from "react";
-import useWebSocket, { ReadyState } from "react-use-websocket";
-import {
- WebsocketBroadcastMessagePayload,
- WebsocketWebsocketMessageType,
-} from "src/phoenix-generated";
-import { useInterval } from "usehooks-ts";
-import { EventPayload } from ".";
-import { EventType, WebsocketContext } from "./WebsocketContext";
-
-export interface WebsocketProviderProps {
- children: React.ReactNode;
-}
-
-const WS_URL =
- import.meta.env.VITE_WS_URL ??
- "wss://n3t271qwr5.execute-api.us-east-1.amazonaws.com/$default";
-const shouldAttemptConnection = true;
-
-export const WebsocketProvider: React.FC<WebsocketProviderProps> = ({
- children,
-}) => {
- const eventListeners = useRef<
- Map<EventType, Set<(payload: WebsocketBroadcastMessagePayload) => void>>
- >(new Map());
- const [connectionId, setConnectionId] = useState<string | null>(null);
-
- const subscribe = useCallback(
- <T extends EventType>(
- eventType: T,
- callback: (payload: WebsocketBroadcastMessagePayload) => void,
- ) => {
- if (!eventListeners.current.has(eventType)) {
- eventListeners.current.set(eventType, new Set());
- }
- eventListeners.current.get(eventType)!.add(callback);
- },
- [],
- );
-
- const unsubscribe = useCallback(
- <T extends EventType>(
- eventType: T,
- callback: (payload: WebsocketBroadcastMessagePayload) => void,
- ) => {
- const listeners = eventListeners.current.get(eventType);
- if (listeners) {
- listeners.delete(callback);
- if (listeners.size === 0) {
- eventListeners.current.delete(eventType);
- }
- }
- },
- [],
- );
-
- const emit = useCallback(
- <T extends EventType>(
- eventType: T,
- payload: WebsocketBroadcastMessagePayload,
- ) => {
- const listeners = eventListeners.current.get(eventType);
- if (listeners) {
- listeners.forEach((callback) => {
- try {
- callback(payload);
- } catch (error) {
- console.error(`Error in event listener for ${eventType}:`, error);
- }
- });
- }
- },
- [],
- );
-
- const onMessage = useCallback(
- (event: MessageEvent) => {
- try {
- const message: WebsocketBroadcastMessagePayload = JSON.parse(
- event.data,
- );
- console.log("Received WebSocket message", message);
-
- if (message) {
- emit(message.type, message);
- }
- } catch (error) {
- console.error("Error parsing WebSocket message:", error);
- }
- },
- [emit],
- );
-
- const { sendJsonMessage: _sendMessage, readyState } = useWebSocket(
- WS_URL,
- {
- onClose: (event) => {
- console.log("Connection closed", event);
- },
- shouldReconnect: () => true,
- onOpen: (event) => {
- console.log("Connection opened", event);
- },
- onMessage,
- onReconnectStop: (numAttempts) => {
- console.log("Reconnect stopped", numAttempts);
- },
- reconnectInterval: 0,
- reconnectAttempts: 2,
- },
- shouldAttemptConnection,
- );
-
- const sendMessage = useCallback(
- <T extends EventType>(payload: EventPayload<T>) => {
- if (readyState === ReadyState.OPEN) {
- _sendMessage(payload);
- } else {
- console.warn(
- `Cannot send message - WebSocket not ready. State: ${readyState}`,
- );
- }
- },
- [_sendMessage, readyState],
- );
-
- // ping every minute (heartbeat)
- useInterval(
- () => {
- if (readyState === ReadyState.OPEN)
- sendMessage({
- type: WebsocketWebsocketMessageType.PING,
- });
- },
- 1000 * 60 * 1,
- );
-
- // request connection info from server once we are connected
- useEffect(() => {
- if (readyState === ReadyState.OPEN) {
- sendMessage({
- type: WebsocketWebsocketMessageType.ConnectionInfoRequest,
- });
- }
- }, [readyState, sendMessage]);
-
- const handleConnectionInfo = useCallback(
- (payload: WebsocketBroadcastMessagePayload) => {
- if (!payload?.connectionInfo?.connectionId) {
- captureException(
- new Error("Connection info response received without connection id"),
- );
- return;
- }
- setConnectionId(payload.connectionInfo.connectionId);
- },
- [],
- );
-
- // once we have a connection id, set it in state
- useEffect(() => {
- subscribe(
- WebsocketWebsocketMessageType.ConnectionInfoResponse,
- handleConnectionInfo,
- );
- return () => {
- unsubscribe(
- WebsocketWebsocketMessageType.ConnectionInfoResponse,
- handleConnectionInfo,
- );
- };
- }, [handleConnectionInfo, subscribe, unsubscribe]);
-
- return (
- <WebsocketContext.Provider
- value={{
- readyState,
- subscribe,
- unsubscribe,
- sendMessage,
- emit,
- connectionId,
- }}
- >
- {children}
- </WebsocketContext.Provider>
- );
-};
diff --git a/src/context/WebsocketContext/index.ts b/src/context/WebsocketContext/index.ts
deleted file mode 100644
index ecb82354..00000000
--- a/src/context/WebsocketContext/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { useWebsocketContext, useWebsocketEvent } from "./useWebsocketContext";
-export { WebsocketContext } from "./WebsocketContext";
-export type { EventPayload, EventType } from "./WebsocketContext";
-export { WebsocketProvider } from "./WebsocketProvider";
diff --git a/src/context/WebsocketContext/useWebsocketContext.tsx b/src/context/WebsocketContext/useWebsocketContext.tsx
deleted file mode 100644
index 0844362f..00000000
--- a/src/context/WebsocketContext/useWebsocketContext.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { useContext, useEffect } from "react";
-import { WebsocketBroadcastMessagePayload } from "src/phoenix-generated";
-import { EventType, WebsocketContext } from "./WebsocketContext";
-
-export const useWebsocketContext = () => {
- const context = useContext(WebsocketContext);
- if (!context) {
- throw new Error(
- "useWebsocketContext must be used within a WebsocketProvider",
- );
- }
- return context;
-};
-
-export const useWebsocketEvent = <T extends EventType>(
- eventType: T,
- callback: (payload: WebsocketBroadcastMessagePayload) => void,
-) => {
- const { subscribe, unsubscribe } = useWebsocketContext();
-
- useEffect(() => {
- subscribe(eventType, callback);
- return () => unsubscribe(eventType, callback);
- }, [eventType, callback, subscribe, unsubscribe]);
-};
diff --git a/src/hooks/useIdleTimer.tsx b/src/hooks/useIdleTimer.tsx
index 190e9473..9d0ca1a9 100644
--- a/src/hooks/useIdleTimer.tsx
+++ b/src/hooks/useIdleTimer.tsx
@@ -10,12 +10,6 @@ const useIdleTimer = (onIdle: () => void, idleTime: number) => {
const hasExecutedRef = useRef(false); // To track if the function has been executed
const isIdleRef = useRef(false);
- // Do not depend on onIdle to be stable
- const onIdleRef = useRef(onIdle);
- useEffect(() => {
- onIdleRef.current = onIdle;
- }, [onIdle]);
-
useEffect(() => {
const resetTimer = () => {
clearTimeout(idleTimerRef.current ?? undefined);
@@ -29,7 +23,7 @@ const useIdleTimer = (onIdle: () => void, idleTime: number) => {
isIdleRef.current = true;
if (!hasExecutedRef.current) {
- onIdleRef.current(); // Execute the function
+ onIdle(); // Execute the function
hasExecutedRef.current = true; // Mark as executed
}
}, idleTime);
diff --git a/src/hooks/useItemDetailTabs.tsx b/src/hooks/useItemDetailTabs.tsx
index 3fb11e9c..5cc0614e 100644
--- a/src/hooks/useItemDetailTabs.tsx
+++ b/src/hooks/useItemDetailTabs.tsx
@@ -113,7 +113,6 @@ export const useItemDetailTabs = (
content: <PurchasedWithTab cohortItemId={entityItem?.cohortItemId} />,
},
];
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
allPossibleEntities.length,
entityItem,
diff --git a/src/hooks/useKeypress.tsx b/src/hooks/useKeypress.tsx
index d2c8fe7d..8f7ea565 100644
--- a/src/hooks/useKeypress.tsx
+++ b/src/hooks/useKeypress.tsx
@@ -47,7 +47,6 @@ export const useKeypress = (
}
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[mapping],
);
diff --git a/src/hooks/useMenuConfig.tsx b/src/hooks/useMenuConfig.tsx
index 7ea64ef6..e6f400cd 100644
--- a/src/hooks/useMenuConfig.tsx
+++ b/src/hooks/useMenuConfig.tsx
@@ -429,7 +429,6 @@ export const useMenuConfig = (): {
],
},
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
register.isRegisterOpen,
register.registerNumber,
diff --git a/src/hooks/useOrderItemDecisionUpdater.ts b/src/hooks/useOrderItemDecisionUpdater.ts
deleted file mode 100644
index b041b7f9..00000000
--- a/src/hooks/useOrderItemDecisionUpdater.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { useToast } from "components/ui/use-toast";
-import { captureException } from "config/sentry/TransformitySentry";
-import { useState } from "react";
-import { useUpdateOrderItemDecisionStatus } from "src/phoenix-generated";
-import { typeid } from "typeid-js";
-
-interface DecisionUpdate {
- decisionId: string;
- status: "ACCEPTED" | "REJECTED";
- reason?: string;
- userId: string;
- source?: string;
-}
-
-interface UpdaterOptions {
- onSuccess?: () => void;
- onError?: (error: any) => void;
-}
-
-export const useOrderItemDecisionUpdater = (options: UpdaterOptions = {}) => {
- const { toast } = useToast();
- const [isUpdating, setIsUpdating] = useState(false);
-
- const { mutateAsync: updateOrderItemDecisionStatus } =
- useUpdateOrderItemDecisionStatus({
- mutation: {
- onSuccess: () => {
- options.onSuccess?.();
- },
- onError: (err: any) => {
- const errorMessage =
- err.response?.data?.message || "Failed to update decision";
- toast({
- title: "Error",
- description: errorMessage,
- variant: "destructive",
- });
- captureException(err);
- options.onError?.(err);
- },
- },
- });
-
- const updateDecisions = async (updates: DecisionUpdate[]) => {
- if (updates.length === 0) return;
-
- setIsUpdating(true);
- try {
- await Promise.all(
- updates.map((update) =>
- updateOrderItemDecisionStatus({
- id: update.decisionId,
- data: {
- status: update.status,
- decisionMadeById: update.userId,
- decisionTime: new Date().toISOString(),
- metadata: {
- decisionContext: {
- batchId: typeid("ordibat").toString(),
- source: update.source || "unknown",
- },
- },
- // @ts-expect-error - TODO: fix this in generator
- fulfillmentId: null,
- reason:
- update.reason ||
- `${update.status.toLowerCase()} via cashier interface`,
- },
- }),
- ),
- );
-
- const successMessage =
- updates.length === 1
- ? `Decisions updated`
- : `${updates.length} item(s) updated. Remember to prepare the accepted items for pickup.`;
-
- toast({
- title: "Success",
- description: successMessage,
- variant: "success",
- });
- } catch (error) {
- // Error handling is done in the mutation onError
- } finally {
- setIsUpdating(false);
- }
- };
-
- return {
- updateDecisions,
- isUpdating,
- };
-};
diff --git a/src/hooks/usePostHogFeatureFlag.ts b/src/hooks/usePostHogFeatureFlag.ts
index 2b0629d1..86a2673e 100644
--- a/src/hooks/usePostHogFeatureFlag.ts
+++ b/src/hooks/usePostHogFeatureFlag.ts
@@ -1,4 +1,3 @@
-import { useStatsigClient } from "@statsig/react-bindings";
import { captureException } from "config/sentry/TransformitySentry";
import { usePostHog } from "posthog-js/react";
import { useEffect, useState } from "react";
@@ -8,16 +7,13 @@ export function useFeatureFlagEnabled(
flag: string,
defaultValue: boolean = false,
): boolean {
- const posthogClient = usePostHog();
- const { client: statsigClient } = useStatsigClient();
+ const client = usePostHog();
const [query] = useQueryParam(flag, BooleanParam);
const [featureEnabled, setFeatureEnabled] = useState<boolean | undefined>(
() => {
try {
- return (
- posthogClient.isFeatureEnabled(flag) || statsigClient.checkGate(flag)
- );
+ return client.isFeatureEnabled(flag);
} catch (error) {
captureException(error);
return defaultValue;
@@ -26,21 +22,17 @@ export function useFeatureFlagEnabled(
);
useEffect(() => {
- return posthogClient.onFeatureFlags(() => {
+ return client.onFeatureFlags(() => {
setFeatureEnabled((prev) => {
try {
- return (
- posthogClient.isFeatureEnabled(flag) ||
- statsigClient.checkGate(flag)
- );
+ return client.isFeatureEnabled(flag);
} catch (error) {
captureException(error);
return prev ?? defaultValue; // Ensure a boolean is always returned
}
});
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [posthogClient, statsigClient, flag]);
+ }, [client, flag]);
const val = query ?? featureEnabled ?? defaultValue;
console.log(`Feature flag "${flag}" is ${val ? "enabled" : "disabled"}.`);
diff --git a/src/hooks/usePrintTransactionTotalsReceipt.tsx b/src/hooks/usePrintTransactionTotalsReceipt.tsx
index dd99ca58..9525fd2a 100644
--- a/src/hooks/usePrintTransactionTotalsReceipt.tsx
+++ b/src/hooks/usePrintTransactionTotalsReceipt.tsx
@@ -417,7 +417,6 @@ export const usePrintTransactionTotalsReceipt = () => {
</Printer>,
);
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[printerWidth, sendReceiptData, entity.id],
);
diff --git a/src/hooks/useSalesChannelWizard.ts b/src/hooks/useSalesChannelWizard.ts
deleted file mode 100644
index 7c34d3d2..00000000
--- a/src/hooks/useSalesChannelWizard.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { captureException } from "@sentry/react";
-import { useCallback } from "react";
-import { useToast } from "src/components/ui/use-toast";
-import {
- EntitySalesChannel,
- UpsertEntitySalesChannelPaymentMethodDto,
- UpsertSalesChannel,
- useCreateEntitySalesChannelPaymentMethod,
- useUpsertEntitySalesChannel,
-} from "src/spring-generated";
-
-// Form data type that includes payment methods
-export type SalesChannelFormData = UpsertSalesChannel & {
- paymentMethods: Array<
- UpsertEntitySalesChannelPaymentMethodDto & { isDefault: boolean }
- >;
-};
-
-interface UseSalesChannelWizardProps {
- onSuccess?: (channel: EntitySalesChannel) => void;
- onClose?: () => void;
-}
-
-export const useSalesChannelWizard = ({
- onSuccess,
- onClose,
-}: UseSalesChannelWizardProps) => {
- const { toast } = useToast();
-
- const { mutateAsync: upsertSalesChannel } = useUpsertEntitySalesChannel();
- const { mutateAsync: createPaymentMethod } =
- useCreateEntitySalesChannelPaymentMethod();
-
- const handleComplete = useCallback(
- async (data: SalesChannelFormData) => {
- try {
- // Step 1: Create EntitySalesChannel without default payment method
- const salesChannelData: UpsertSalesChannel = {
- ...data,
- defaultPaymentMethodId: undefined, // Will be set later
- };
-
- const createdSalesChannel = await upsertSalesChannel({
- data: salesChannelData,
- });
-
- // Step 2: Create all payment methods
- const paymentMethodPromises = data.paymentMethods.map(
- async (method) => {
- const paymentMethodData: UpsertEntitySalesChannelPaymentMethodDto =
- {
- entityId: data.entityId,
- entitySalesChannelId: createdSalesChannel.id,
- paymentMethodType: method.paymentMethodType,
- cohortPriceLevelId: method.cohortPriceLevelId,
- displayOnPayButton: method.displayOnPayButton,
- isArchived: false,
- };
-
- return await createPaymentMethod({
- data: paymentMethodData,
- });
- },
- );
-
- const createdPaymentMethods = await Promise.all(paymentMethodPromises);
-
- // Step 3: Find default payment method and update sales channel
- const defaultPaymentMethodIndex = data.paymentMethods.findIndex(
- (pm) => pm.isDefault,
- );
- const defaultPaymentMethod =
- createdPaymentMethods[defaultPaymentMethodIndex];
-
- if (defaultPaymentMethod?.id) {
- await upsertSalesChannel({
- data: {
- ...salesChannelData,
- id: createdSalesChannel.id,
- defaultPaymentMethodId: defaultPaymentMethod.id,
- priceLevelId: defaultPaymentMethod.cohortPriceLevelId,
- },
- });
- }
-
- toast({
- title: "Sales channel created",
- description: "Your sales channel has been created successfully",
- });
-
- onSuccess?.(createdSalesChannel);
- onClose?.();
- } catch (error) {
- captureException(error, {
- tags: { component: "SalesChannelWizard" },
- level: "error",
- });
-
- toast({
- variant: "destructive",
- title: "Error creating sales channel",
- description:
- error instanceof Error
- ? error.message
- : "An unexpected error occurred",
- });
- throw error;
- }
- },
- [upsertSalesChannel, createPaymentMethod, toast, onSuccess, onClose],
- );
-
- return {
- handleComplete,
- };
-};
diff --git a/src/hooks/useStorefrontDecisionHandler.tsx b/src/hooks/useStorefrontDecisionHandler.tsx
deleted file mode 100644
index c55e5e2c..00000000
--- a/src/hooks/useStorefrontDecisionHandler.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { useEntity } from "context/EntityProvider";
-import {
- useWebsocketContext,
- useWebsocketEvent,
-} from "context/WebsocketContext";
-import { useEffect, useState } from "react";
-import { ReadyState } from "react-use-websocket";
-import {
- createWebsocketConnection,
- removeWebsocketConnection,
- WebsocketBroadcastMessagePayload,
- WebsocketWebsocketMessageType,
-} from "src/phoenix-generated";
-import { useIsMounted } from "usehooks-ts";
-
-/**
- * @param enabled - whether to enable the handler
- * @param onDecision - callback to handle the decision. Make stable reference to avoid re-renders.
- */
-export const useStorefrontDecisionHandler = (
- enabled: boolean,
- onDecision: (payload: WebsocketBroadcastMessagePayload) => void,
-) => {
- const { connectionId, readyState } = useWebsocketContext();
- const [entity] = useEntity();
- const [wsConnectionId, setWsConnectionId] = useState<number | null>(null);
-
- const mounted = useIsMounted();
-
- useEffect(() => {
- if (
- enabled &&
- connectionId &&
- readyState === ReadyState.OPEN &&
- !wsConnectionId &&
- entity?.id
- ) {
- console.log("Creating websocket connection");
- void createWebsocketConnection({
- connectionId,
- topic: WebsocketWebsocketMessageType.OrderItemDecision,
- entityId: entity?.id,
- }).then((res) => {
- if (mounted()) {
- setWsConnectionId(res.id);
- }
- });
- }
- return () => {
- if (connectionId && wsConnectionId) {
- if (mounted()) {
- console.log("Removing websocket connection", connectionId);
- void removeWebsocketConnection(connectionId).then(() => {
- setWsConnectionId(null);
- });
- }
- }
- };
- }, [connectionId, readyState, entity?.id, enabled, wsConnectionId, mounted]);
-
- useWebsocketEvent(
- WebsocketWebsocketMessageType.OrderItemDecision,
- onDecision,
- );
-};
diff --git a/src/index.tsx b/src/index.tsx
index 2367ecfd..b22418d9 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -7,12 +7,9 @@ import { theme } from "./theme";
// 2. Update the breakpoints as key-value pairs
-import { StatsigProvider, useClientAsyncInit } from "@statsig/react-bindings";
-import { StatsigSessionReplayPlugin } from "@statsig/session-replay";
-import { StatsigAutoCapturePlugin } from "@statsig/web-analytics";
import { PostHogConfig } from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
-import { ReactNode, useEffect } from "react";
+import { ReactNode, StrictMode, useEffect } from "react";
import {
createRoutesFromChildren,
matchRoutes,
@@ -27,10 +24,13 @@ import {
} from "./config/sentry/TransformitySentry";
// Import the dev tools and initialize them
-import Loading from "components/Loading";
import { Toaster } from "components/ui/toaster";
import { SentryErrorBoundary } from "config/sentry/SentryErrorBoundary";
+import { TempoDevtools } from "tempo-devtools";
import { isIOS } from "utils/deviceUtils";
+if (import.meta.env.VITE_TEMPO) {
+ TempoDevtools.init();
+}
console.log("NODE_ENV", import.meta.env.NODE_ENV);
console.log("NODE_ENV PROD", import.meta.env.PROD);
@@ -73,6 +73,8 @@ sentryInit({
tracePropagationTargets: [/^https:\/\/api.transformity\.tech\//],
}),
replayIntegration({
+ sessionSampleRate: 0,
+ errorSampleRate: 1.0,
maskAllText: false,
maskAllInputs: false,
networkDetailAllowUrls: [
@@ -98,7 +100,7 @@ sentryInit({
// Performance Monitoring
tracesSampleRate: 1.0, // Capture 100% of the transactions
// Session Replay
- replaysSessionSampleRate: 0.0, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
+ replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
enabled: import.meta.env.PROD && !isIOS(),
});
@@ -118,11 +120,6 @@ const PostHogProviderWrapper = ({ children }: { children: ReactNode }) => {
disable_session_recording: !isProd, // Only in production
enable_recording_console_log: isProd, // Only in production
capture_performance: isProd, // Only in production
- bootstrap: {
- featureFlags: {
- offline_mode_data_sync: false,
- },
- },
session_recording: {
recordHeaders: true,
recordBody: true,
@@ -143,44 +140,12 @@ const PostHogProviderWrapper = ({ children }: { children: ReactNode }) => {
);
};
-const StatsigProviderWrapper = ({ children }: { children: ReactNode }) => {
- const isProd = import.meta.env.PROD;
- const { client } = useClientAsyncInit(
- import.meta.env.VITE_APP_PUBLIC_STATSIG_CLIENT_KEY,
- { userID: undefined },
- {
- plugins: [
- new StatsigSessionReplayPlugin({
- rrwebConfig: {
- maskAllInputs: false,
- maskInputOptions: {
- password: true,
- },
- },
- }),
- new StatsigAutoCapturePlugin({
- consoleLogAutoCaptureSettings: {
- enabled: false,
- },
- }),
- ],
- environment: { tier: isProd ? "production" : "development" },
- },
- );
-
- return (
- <StatsigProvider client={client} loadingComponent={<Loading />}>
- {children}
- </StatsigProvider>
- );
-};
-
root.render(
- <ChakraProvider
- toastOptions={{ defaultOptions: { position: "top" } }}
- theme={theme}
- >
- <StatsigProviderWrapper>
+ <StrictMode>
+ <ChakraProvider
+ toastOptions={{ defaultOptions: { position: "top" } }}
+ theme={theme}
+ >
<PostHogProviderWrapper>
<SentryErrorBoundary>
<App />
@@ -188,6 +153,6 @@ root.render(
<SonnerToaster />
</SentryErrorBoundary>
</PostHogProviderWrapper>
- </StatsigProviderWrapper>
- </ChakraProvider>,
+ </ChakraProvider>
+ </StrictMode>,
);
diff --git a/src/pages/Auth/AuthorizationGuard.tsx b/src/pages/Auth/AuthorizationGuard.tsx
index 31291dd8..6e625d03 100644
--- a/src/pages/Auth/AuthorizationGuard.tsx
+++ b/src/pages/Auth/AuthorizationGuard.tsx
@@ -12,8 +12,6 @@ import { EmployeeOverrideHandlerProvider } from "context/AuthorizationContext/Em
import { useAuthorization } from "context/AuthorizationContext/useAuthorizationContext";
import { useEntity } from "context/EntityProvider";
import { PermissionsProvider } from "context/PermissionsContext";
-import { StorefrontProvider } from "context/StorefrontContext/StorefrontProvider";
-import { WebsocketProvider } from "context/WebsocketContext";
import { EntityConfigKey } from "generated/types";
import { useEntityConfig } from "hooks/useEntityConfig";
import { usePostHog } from "posthog-js/react";
@@ -21,7 +19,6 @@ import { useEffect, useRef } from "react";
import { Outlet, useNavigate } from "react-router-dom";
import { SelectStoreForm } from "../../components/Auth/AuthorizationFlowForms/SelectStoreForm";
import Loading from "../../components/Loading";
-import { SubscriptionBannerWrapper } from "../../components/SubscriptionBannerWrapper";
import { CenteredLayout } from "../../components/layouts/CenteredLayout";
import { useIdleTime } from "../../hooks/useIdleTime";
import { EmployeePinLoginCard } from "./EmployeePinLoginCard";
@@ -95,16 +92,11 @@ const AuthorizationGuard: React.FC<AuthorizationFlowProps> = () => {
if (entity && !isStoreLogin && user && permissions) {
return (
<PermissionsProvider permissions={permissions}>
- <WebsocketProvider>
- <EmployeeOverrideHandlerProvider>
- <RemoteAccessGuard>
- <StorefrontProvider>
- <SubscriptionBannerWrapper />
- <Outlet />
- </StorefrontProvider>
- </RemoteAccessGuard>
- </EmployeeOverrideHandlerProvider>
- </WebsocketProvider>
+ <EmployeeOverrideHandlerProvider>
+ <RemoteAccessGuard>
+ <Outlet />
+ </RemoteAccessGuard>
+ </EmployeeOverrideHandlerProvider>
</PermissionsProvider>
);
}
diff --git a/src/pages/Auth/SignIn.tsx b/src/pages/Auth/SignIn.tsx
index 40b03ab4..62f0fa8c 100644
--- a/src/pages/Auth/SignIn.tsx
+++ b/src/pages/Auth/SignIn.tsx
@@ -35,7 +35,7 @@ const SignIn = () => {
const handleGoogleSignIn = async () => {
setError("");
try {
- await googleSignIn();
+ await googleSignIn!();
} catch (e: any) {
if (e.message.includes("(auth/popup-closed-by-user)")) {
setError("Sign In with Google Canceled");
@@ -47,7 +47,7 @@ const SignIn = () => {
const handleForgotPassword = async (email: string) => {
try {
- await triggerResetEmail(email);
+ await triggerResetEmail!(email);
setError("A password reset link has been sent to your email address.");
} catch (e: any) {
setError(e.message);
diff --git a/src/pages/CannyFeedback.tsx b/src/pages/CannyFeedback.tsx
index d72ba993..8ea3ab1c 100644
--- a/src/pages/CannyFeedback.tsx
+++ b/src/pages/CannyFeedback.tsx
@@ -1,7 +1,11 @@
+
+
// @ts-nocheck
+import { CommandMenuShortcutOverlay } from "components/common/CommandMenuShortcutOverlay";
+import { useCannyApi } from "config/ItemsApi";
import { useDocumentTitle } from "hooks/useDocumentTitle";
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
import { NavBarPlain } from "../components/navbar/NavBarPlain";
import { useGetCannySsoToken } from "../generated/hooks/useGetCannySsoToken";
@@ -59,6 +63,7 @@ const Feedback = () => {
className="h-full overflow-y-auto"
>
<div data-canny />
+ <CommandMenuShortcutOverlay withOverlay={true} />
</div>
</>
);
diff --git a/src/pages/RegisterOpeningPage.tsx b/src/pages/RegisterOpeningPage.tsx
index d4230d9c..472de5a7 100644
--- a/src/pages/RegisterOpeningPage.tsx
+++ b/src/pages/RegisterOpeningPage.tsx
@@ -15,7 +15,7 @@ import {
useToast,
} from "@chakra-ui/react";
import { captureException } from "@sentry/react";
-import type { DrawerReportingFormValues } from "components/DrawerReporting/DrawerReporting";
+import { DrawerReportingFormValues } from "components/DrawerReporting/DrawerReporting";
import { DrawerReportingModal } from "components/DrawerReporting/DrawerReportingModal";
import ChangeRegisterForm from "components/register/ChangeRegisterForm";
import { useEntitySelected } from "context/EntityProvider";
@@ -26,7 +26,7 @@ import { useDocumentTitle } from "hooks/useDocumentTitle";
import { useEntityConfig } from "hooks/useEntityConfig";
import posthog from "posthog-js";
import { useCallback, useEffect, useState } from "react";
-import { Link, Navigate, useNavigate } from "react-router-dom";
+import { Link, useNavigate } from "react-router-dom";
import {
useCreateDrawerCountSettlement,
useGetCurrentOpenDrawerSettlement,
@@ -122,113 +122,119 @@ const RegisterOpeningPage = () => {
},
});
- if (isRegisterOpen.isRegisterOpen) {
- return <Navigate to="/sale/" replace />;
- }
-
return (
- <Stack
- background={"gray.100"}
- display={"flex"}
- justify="flex-start"
- align="center"
- spacing="10px"
- overflow="hidden"
- width="100vw"
- height="100vh"
- maxWidth="100%"
- maxHeight={"100%"}
- overflowY={"auto"}
- >
- <NavBarPlain hideSalesScreenShortcut />
- <DrawerReportingModal
- {...drawerCountingModalDisclosure}
- isPending={isPending}
- headerTitle="Opening Drawer Count"
- submitBtnText="Start Shift"
- registerNumber={registerValue.registerNumber}
- onSubmit={async (data: DrawerReportingFormValues) => {
- await submitOpeningDrawerCount({
- registerId: registerValue.registerNumber,
- data,
- });
- }}
- />
-
- <Card paddingX={"10px"} pb={3} height="auto">
- <CardHeader>
- <Heading size="lg">Select Workstation</Heading>
- </CardHeader>
- <Flex direction={"column"} gap={"3"}>
- <FormControl>
- <Select
- name="register"
- value={registerValue.registerNumber}
- isDisabled={!hasPermission("register/*:change")}
- onChange={(e) => {
- const value = e.currentTarget.value;
-
- if (!value) {
- return;
- }
- return setRegisterValue((prev) => {
- posthog.capture("register_opening_page_select_register", {
- old_register: prev.registerNumber,
- new_register: +value,
- });
- if (prev.registerNumber !== +value) {
- posthog.capture("register_opening_page_register_switched", {
- old_register: prev.registerNumber,
- new_register: +value,
+ <>
+ <Stack
+ background={"gray.100"}
+ display={"flex"}
+ justify="flex-start"
+ align="center"
+ spacing="10px"
+ overflow="hidden"
+ width="100vw"
+ height="100vh"
+ maxWidth="100%"
+ maxHeight={"100%"}
+ overflowY={"auto"}
+ >
+ <NavBarPlain hideSalesScreenShortcut />
+ <DrawerReportingModal
+ {...drawerCountingModalDisclosure}
+ isPending={isPending}
+ headerTitle="Opening Drawer Count"
+ submitBtnText="Start Shift"
+ registerNumber={registerValue.registerNumber}
+ onSubmit={async (data: DrawerReportingFormValues) => {
+ await submitOpeningDrawerCount({
+ registerId: registerValue.registerNumber,
+ data,
+ });
+ }}
+ />
+
+ <Card paddingX={"10px"} pb={3} height="auto">
+ <CardHeader>
+ <Heading size="lg">Select Workstation</Heading>
+ </CardHeader>
+ <Flex direction={"column"} gap={"3"}>
+ <>
+ <FormControl>
+ <Select
+ name="register"
+ value={registerValue.registerNumber}
+ isDisabled={!hasPermission("register/*:change")}
+ onChange={(e) => {
+ const value = e.currentTarget.value;
+
+ if (!value) {
+ return;
+ }
+ return setRegisterValue((prev) => {
+ posthog.capture("register_opening_page_select_register", {
+ old_register: prev.registerNumber,
+ new_register: +value,
+ });
+ if (prev.registerNumber !== +value) {
+ posthog.capture(
+ "register_opening_page_register_switched",
+ {
+ old_register: prev.registerNumber,
+ new_register: +value,
+ },
+ );
+ }
+ return { ...prev, registerNumber: +value };
});
- }
- return { ...prev, registerNumber: +value };
- });
+ }}
+ >
+ {entity.registers
+ .sort((a, b) => a.registerId - b.registerId)
+ .map((register) => (
+ <option
+ value={register.registerId}
+ key={register.registerId}
+ >
+ Register: {register.registerId}
+ </option>
+ ))}
+ </Select>
+ </FormControl>
+ </>
+ <ChangeRegisterForm
+ onSubmit={async () => {
+ if (!!currentOpenDrawerSettlement) {
+ updateRegisterStateAndOpen();
+ } else if (enableDrawerCounting.value) {
+ drawerCountingModalDisclosureOnOpen();
+ } else {
+ await submitOpeningDrawerCount({
+ registerId: registerValue.registerNumber,
+ data: {},
+ });
+ }
}}
- >
- {entity.registers
- .sort((a, b) => a.registerId - b.registerId)
- .map((register) => (
- <option value={register.registerId} key={register.registerId}>
- Register: {register.registerId}
- </option>
- ))}
- </Select>
- </FormControl>
- <ChangeRegisterForm
- onSubmit={async () => {
- if (currentOpenDrawerSettlement) {
- updateRegisterStateAndOpen();
- } else if (enableDrawerCounting.value) {
- drawerCountingModalDisclosureOnOpen();
- } else {
- await submitOpeningDrawerCount({
- registerId: registerValue.registerNumber,
- data: {},
- });
- }
- }}
- disabled={isPending || isFetching}
- selectedRegister={registerValue.registerNumber}
- />
- <Divider orientation="horizontal" />
- <Center>
- <Text>OR</Text>
- </Center>
- <Divider orientation="horizontal" />
- <ChakraLink as={Link} to="/items/search/">
- <Button
- type="submit"
- colorScheme="blue"
- isDisabled={isPending}
- w="100%"
- >
- Back Office
- </Button>
- </ChakraLink>
- </Flex>
- </Card>
- </Stack>
+ disabled={isPending || isFetching}
+ selectedRegister={registerValue.registerNumber}
+ />
+ <Divider orientation="horizontal" />
+ <Center>
+ <Text>OR</Text>
+ </Center>
+ <Divider orientation="horizontal" />
+ <ChakraLink as={Link} to="/items/search/">
+ <Button
+ type="submit"
+ colorScheme="blue"
+ isDisabled={isPending}
+ w="100%"
+ >
+ Back Office
+ </Button>
+ </ChakraLink>
+ </Flex>
+ </Card>
+ </Stack>
+ </>
);
};
diff --git a/src/pages/SalePage/SalePage.tsx b/src/pages/SalePage/SalePage.tsx
index e4e7837f..35d3152c 100644
--- a/src/pages/SalePage/SalePage.tsx
+++ b/src/pages/SalePage/SalePage.tsx
@@ -11,6 +11,7 @@ import { useEntitySelected } from "context/EntityProvider";
import { useRegisterProvider } from "context/RegisterProvider";
import { SalesContextType, useSalesContext } from "context/Sales/SalesContext";
import { useEffect, useMemo, useRef } from "react";
+import usePoleDisplay from "../../components/PoleDisplay";
import { QtyHotKeys } from "../../components/QtyHotKeys";
import { BottomLine } from "../../components/SalesScreenComponents/BottomLine/BottomLine";
import { ItemNotInSystemAlert } from "../../components/SalesScreenComponents/Modals/ItemNotInSystemAlert";
@@ -20,15 +21,9 @@ import { QuickPicks } from "../../components/SalesScreenComponents/SalesButtonGr
import { SalesScreenItemsTable } from "../../components/SalesScreenComponents/SalesScreenItemsTable";
import SaleScreenNavBar from "../../components/navbar/SaleScreenNavBar";
-import { usePGlite } from "@electric-sql/pglite-react";
-import { SalePageSyncOverlay } from "components/SalePageSyncOverlay";
import { VariablePriceModal } from "components/SalesScreenComponents/Modals/VariablePriceModal";
import { useSalePageConfig } from "components/SalesScreenComponents/SalePageConfigProvider";
import { TotalSummaryCard } from "components/SalesScreenComponents/TotalSummaryCard";
-import {
- RetrieveItemsByUpc,
- RetrieveItemsByUpcQuery,
-} from "components/pg-lite/queries/RetrieveItemsByUpc";
import { ComboboxSelectRef } from "components/ui/ComboboxSelect";
import { usePermissions } from "context/PermissionsContext";
import {
@@ -40,10 +35,11 @@ import useIdleTimer from "hooks/useIdleTimer";
import { Navigate } from "react-router-dom";
import { BottomLineRight } from "src/components/SalesScreenComponents/BottomLine/BottomLineRight";
import { SaleStep } from "src/components/SalesScreenComponents/Modals/ReviewSaleModal/ReviewSaleModal";
-import { TransactionPaymentForm } from "src/generated/types";
+import { EntityItemDetail } from "src/generated";
import { EntityConfigKey } from "src/generated/types/EntityConfigKey";
import { useEntityConfig } from "src/hooks/useEntityConfig";
import { useGetAllDepartmentsForEntity } from "src/hooks/useGetAllDepartmentsForEntity";
+import { USDollar } from "src/utils/dollarFormat";
import Loading from "../../components/Loading";
import { useKeypress } from "../../hooks/useKeypress";
import { playFailureSound, playStopSound } from "../../utils/audioUtils";
@@ -69,7 +65,6 @@ const SalePage = () => {
transactionTotalPrice,
clearCart,
taxExempt,
- discount,
governmentID,
setGovernmentID,
customer,
@@ -78,15 +73,8 @@ const SalePage = () => {
setTransactionId,
isCalculatingCartPrice,
isGetCartPricingError,
- calculateCartPrice,
- paymentMethodTypeToPaymentMethod,
- calculateMethodsWithPrices,
- findBestPaymentMethod,
- isCalculatingBackgroundPaymentMethodTotals,
- setSkipSetItemsInCart,
} = useSalesContext();
- const { selectedSalesChannel, overriddenCohortPriceLevel } =
- useSalePageConfig();
+ const { selectedSalesChannel } = useSalePageConfig();
const { value: payAfterConfirm } = useEntityConfig(
EntityConfigKey.PAY_AFTER_CONFIRM,
false,
@@ -97,49 +85,29 @@ const SalePage = () => {
if (!departmentMap) return <Loading />;
return (
- <SalePageSyncOverlay>
- <SalesPaymentProvider
- salePaymentType="sale"
- isGetCartPricingError={isGetCartPricingError}
- isCalculatingCartPrice={isCalculatingCartPrice}
- key={payAfterConfirm ? "pay-after-confirm" : "pay-before-confirm"}
- salesChannel={selectedSalesChannel}
- overriddenCohortPriceLevel={overriddenCohortPriceLevel}
- transactionId={transactionId}
- setTransactionId={setTransactionId}
- transactionItems={convertToTransactionItems(
- itemDetails,
- taxExempt,
- departmentMap,
- )}
- transactionTotalPrice={transactionTotalPrice}
- clearCart={clearCart}
- governmentID={governmentID}
- setGovernmentID={setGovernmentID}
- customer={customer}
- resetCartToCurrentItems={resetCartToCurrentItems}
- payAfterConfirm={payAfterConfirm}
- calculateCartPrice={async (paymentMethodId?: string) =>
- await calculateCartPrice({
- requestedItems: itemDetails,
- requestTaxExempt: taxExempt,
- requestedCustomer: customer,
- requestedDiscount: discount,
- paymentMethodId: paymentMethodId,
- })
- }
- paymentMethodTypeToPaymentMethod={paymentMethodTypeToPaymentMethod}
- calculateMethodsWithPrices={calculateMethodsWithPrices}
- findBestPaymentMethod={findBestPaymentMethod}
- isCalculatingBackgroundPaymentMethodTotals={
- isCalculatingBackgroundPaymentMethodTotals
- }
- selectedSalesChannel={selectedSalesChannel}
- setSkipSetItemsInCart={setSkipSetItemsInCart}
- >
- <SalePageInner />
- </SalesPaymentProvider>
- </SalePageSyncOverlay>
+ <SalesPaymentProvider
+ salePaymentType="sale"
+ isGetCartPricingError={isGetCartPricingError}
+ isCalculatingCartPrice={isCalculatingCartPrice}
+ key={payAfterConfirm ? "pay-after-confirm" : "pay-before-confirm"}
+ salesChannel={selectedSalesChannel}
+ transactionId={transactionId}
+ setTransactionId={setTransactionId}
+ transactionItems={convertToTransactionItems(
+ itemDetails,
+ taxExempt,
+ departmentMap,
+ )}
+ transactionTotalPrice={transactionTotalPrice}
+ clearCart={clearCart}
+ governmentID={governmentID}
+ setGovernmentID={setGovernmentID}
+ customer={customer}
+ resetCartToCurrentItems={resetCartToCurrentItems}
+ payAfterConfirm={payAfterConfirm}
+ >
+ <SalePageInner />
+ </SalesPaymentProvider>
);
};
@@ -159,9 +127,7 @@ export const SalePageInner = () => {
taxExempt,
customer,
discount,
- paymentMethodTypeToPaymentMethod,
} = useSalesContext();
- const db = usePGlite();
const {
lastChangeDue,
payWithCashModal,
@@ -200,6 +166,7 @@ export const SalePageInner = () => {
});
const [entity, , isEntityLoading] = useEntitySelected();
const { register } = useRegisterProvider();
+ const poleDisplay = usePoleDisplay();
const { hasPermission } = usePermissions();
const { value: barcodeExactMatch } = useEntityConfig(
EntityConfigKey.EXACT_BARCODE_LOOKUP,
@@ -365,7 +332,7 @@ export const SalePageInner = () => {
qRegex,
(_?: KeyboardEvent) => {
if (barCodeScannerInput) {
- setQuantity(parseInt(barCodeScannerInput.join(""), 10));
+ setQuantity(parseInt(barCodeScannerInput.join("")));
barCodeScannerInput = undefined;
}
},
@@ -436,19 +403,9 @@ export const SalePageInner = () => {
if (saleStep === SaleStep.Payment) {
barCodeScannerInput = undefined;
if (itemDetails.size && transactionTotalPrice() > 0) {
- // Check if there are multiple credit card methods
- const creditCardMethods =
- paymentMethodTypeToPaymentMethod[
- TransactionPaymentForm["CREDIT CARD"]
- ] || [];
-
- // Only allow F8 if there's one or no credit card methods
- if (creditCardMethods.length <= 1) {
- creditCardPaid(undefined, creditCardMethods[0]?.id);
- creditCardModalV2.onOpen();
- reviewTransactionModal.onClose();
- }
- // If there are multiple methods, F8 is disabled (do nothing)
+ creditCardPaid();
+ creditCardModalV2.onOpen();
+ reviewTransactionModal.onClose();
}
}
},
@@ -488,6 +445,12 @@ export const SalePageInner = () => {
barCodeScannerInput = undefined;
}, 1000);
+ // Update the pole display when the last change due is updated.
+ useEffect(() => {
+ if (lastChangeDue === undefined) return;
+ void poleDisplay("Change Due:", `${USDollar.format(lastChangeDue)}`);
+ }, [lastChangeDue, poleDisplay]);
+
if (isEntityLoading) return <Loading />;
if (!register.isRegisterOpen) {
@@ -510,20 +473,10 @@ export const SalePageInner = () => {
>
<SaleScreenNavBar
ref={searchBoxRef}
- onSearchSelected={async (entityItem) => {
- if (!entityItem) return;
+ onSearchSelected={(itemSelected) => {
+ if (!itemSelected) return;
if (!hasPermission("pos/*:add-from-search")) return;
- const options = RetrieveItemsByUpcQuery(entity.id, null, [
- entityItem.id,
- ]);
- const eRes = await db.query<RetrieveItemsByUpc>(
- options.query,
- options.params,
- );
- const eItem = eRes.rows?.[0];
- if (eItem) {
- addSingleItemToCart(eItem, quantity);
- }
+ addSingleItemToCart(itemSelected as EntityItemDetail, quantity);
}}
/>
<Stack direction={"row"} px={5} flex={2}>
diff --git a/src/pages/SalePage/SalePageUtils.tsx b/src/pages/SalePage/SalePageUtils.tsx
index 226362c2..dbba7d59 100644
--- a/src/pages/SalePage/SalePageUtils.tsx
+++ b/src/pages/SalePage/SalePageUtils.tsx
@@ -1,4 +1,3 @@
-import { RetrieveItemsByUpc } from "components/pg-lite/queries/RetrieveItemsByUpc";
import {
CalculationMetadata,
CartDiscountType,
@@ -13,7 +12,7 @@ import {
import { Department } from "src/spring-generated";
export type LineItem = DraftTransactionItemInput & {
id: TransactionItemId;
- item?: RetrieveItemsByUpc;
+ item?: EntityItemDetail;
/** Discount requested on this line item. */
lineItemDiscount?: Discount;
subtotal: number;
@@ -33,22 +32,22 @@ export const toPercentage = (price: number, discount?: Discount): number => {
};
export function addSingleItem(
- retrievedItem: RetrieveItemsByUpc,
+ retrievedItem: EntityItemDetail,
transactionId: number,
quantity = 1,
taxExempt = false,
priceAtCost: boolean = false,
): Omit<LineItem, "id"> & { id?: number } {
const lineItem: Omit<LineItem, "id"> & { id?: number } = {
- itemId: retrievedItem.ei_id,
+ itemId: retrievedItem.id,
transactionId: transactionId,
- price: +(priceAtCost
- ? (retrievedItem.ei_cost ?? retrievedItem.ei_price)
- : retrievedItem.ei_price),
+ price: priceAtCost
+ ? (retrievedItem.cost ?? retrievedItem.price)
+ : retrievedItem.price,
item: retrievedItem,
- name: retrievedItem.ci_name,
- originalPrice: +retrievedItem.ei_price,
- department: retrievedItem.ci_department,
+ name: retrievedItem.cohortItem.name,
+ originalPrice: retrievedItem.price,
+ department: retrievedItem.cohortItem.department.id,
quantity: 0,
tax: 0,
taxRate: 0,
diff --git a/src/pages/Settings/AboutStore/AboutStorePanel.tsx b/src/pages/Settings/AboutStore/AboutStorePanel.tsx
index 8a5449a3..c560634c 100644
--- a/src/pages/Settings/AboutStore/AboutStorePanel.tsx
+++ b/src/pages/Settings/AboutStore/AboutStorePanel.tsx
@@ -4,7 +4,6 @@ import { USStateSelect } from "components/common/USStateSelect/USStateSelect";
import { FormInput } from "components/CreateItem/common/FormInput";
import { FormLabel } from "components/CreateItem/common/FormLabel";
import { SettingsBlock } from "components/SettingsComponents/SettingsBlock";
-import { SubscriptionStatusBadge } from "components/SubscriptionStatusBadge";
import { Button } from "components/ui/button";
import {
Form,
@@ -13,7 +12,6 @@ import {
FormItem,
FormMessage,
} from "components/ui/form";
-import { LoadingSpinner } from "components/ui/loading-spinner";
import {
Select,
SelectContent,
@@ -23,16 +21,10 @@ import {
} from "components/ui/select";
import { useToast } from "components/ui/use-toast";
import { captureException } from "config/sentry/TransformitySentry";
-import { useAppVersion } from "context/AppVersionContext";
import { useEntitySelected } from "context/EntityProvider";
-import { usePermissions } from "context/PermissionsContext";
import { useDocumentTitle } from "hooks/useDocumentTitle";
-import { CreditCard, Receipt } from "lucide-react";
-import { useMemo } from "react";
import { ControllerRenderProps, FieldPath, useForm } from "react-hook-form";
import { usePatchEntity } from "src/spring-generated";
-import { useGenerateEntitySubscriptionPaymentLink } from "src/spring-generated/hooks/useGenerateEntitySubscriptionPaymentLink";
-import { useGetEntitySubscriptionStatus } from "src/spring-generated/hooks/useGetEntitySubscriptionStatus";
import type { AddressRequest } from "src/spring-generated/types/AddressRequest";
import { extractAxios400ErrorMessage } from "utils/errors";
import * as z from "zod";
@@ -58,27 +50,8 @@ type AboutStoreFormValues = z.infer<typeof AboutStoreFormSchema>;
export const AboutStorePanel = () => {
useDocumentTitle("Settings - About Store");
- const { currentVersion, originDomain, stackName, servedFrom } =
- useAppVersion();
const [entity, refreshEntity] = useEntitySelected();
const { toast } = useToast();
- const { hasPermission } = usePermissions();
- const hasSubscriptionReadStatusPermission = useMemo(
- () =>
- hasPermission("esub/*:read_status") &&
- entity.subscriptionId !== undefined &&
- entity.subscriptionId !== null &&
- entity.subscriptionId !== "",
- [hasPermission, entity?.subscriptionId],
- );
- const hasSubscriptionReadPaymentLinkPermission = useMemo(
- () =>
- hasPermission("esub/*:read_payment_link") &&
- entity.customerId !== undefined &&
- entity.customerId !== null &&
- entity.customerId !== "",
- [hasPermission, entity?.customerId],
- );
const { mutateAsync: patchEntity, isPending } = usePatchEntity({
mutation: {
@@ -247,15 +220,6 @@ export const AboutStorePanel = () => {
label="Merchant Processor Account ID"
value={entity.creditCardMerchantId ?? "N/A"}
/>
- <ReadOnlyField label="Version" value={currentVersion} />
- <ReadOnlyField
- label="Stack Name"
- value={stackName ?? "Unknown"}
- />
- <ReadOnlyField
- label="Served From"
- value={servedFrom ?? "Unknown"}
- />
<ReadOnlyField
label="Surcharge Fee"
value={entity.surchargeFee ? "YES" : "NO"}
@@ -376,17 +340,6 @@ export const AboutStorePanel = () => {
</div>
</form>
</Form>
- {(hasSubscriptionReadStatusPermission ||
- hasSubscriptionReadPaymentLinkPermission) && (
- <BillingSection
- hasSubscriptionReadStatusPermission={
- hasSubscriptionReadStatusPermission
- }
- hasSubscriptionReadPaymentLinkPermission={
- hasSubscriptionReadPaymentLinkPermission
- }
- />
- )}
</SettingsBlock>
);
};
@@ -459,128 +412,3 @@ const EditableField = <T extends FieldPath<AboutStoreFormValues>>({
)}
/>
);
-
-const BillingSection = ({
- hasSubscriptionReadStatusPermission,
- hasSubscriptionReadPaymentLinkPermission,
-}: {
- hasSubscriptionReadStatusPermission: boolean;
- hasSubscriptionReadPaymentLinkPermission: boolean;
-}) => {
- const [entity] = useEntitySelected();
- const { toast } = useToast();
-
- // Get subscription status
- const { data: subscriptionStatus } = useGetEntitySubscriptionStatus(
- {
- entityId: entity?.id ?? 0,
- },
- {
- query: {
- enabled: !!entity?.id && hasSubscriptionReadStatusPermission,
- queryKey: ["entitySubscriptionStatus", entity?.id],
- throwOnError: false,
- },
- },
- );
-
- // Get payment link mutation
- const {
- mutateAsync: generatePaymentLink,
- isPending: isGeneratingPaymentLink,
- } = useGenerateEntitySubscriptionPaymentLink({
- mutation: {
- onSuccess: (paymentUrl) => {
- // Open payment link in new tab
- if (
- paymentUrl === "" ||
- paymentUrl === null ||
- paymentUrl === undefined
- ) {
- toast({
- title: "Error generating payment link",
- description:
- "Please contact DrinksPOS Support. Your customer id may not be set in our system yet.",
- variant: "destructive",
- });
- return;
- }
- window.open(paymentUrl, "_blank");
- },
- },
- });
-
- const handlePaymentClick = async () => {
- if (!entity?.id) return;
-
- try {
- await generatePaymentLink({
- params: {
- entityId: entity.id,
- },
- });
- } catch (error) {
- console.error("Error generating payment link:", error);
- captureException(error);
- toast({
- title: "Error generating payment link",
- description: "Failed to generate payment link. Please try again.",
- variant: "destructive",
- duration: 6000,
- });
- }
- };
-
- if (
- !(
- hasSubscriptionReadStatusPermission ||
- hasSubscriptionReadPaymentLinkPermission ||
- !subscriptionStatus
- )
- ) {
- return null;
- }
-
- return (
- <div className="mt-8 w-full">
- <div className="flex items-center justify-between mb-4">
- <div>
- <h2 className="text-xl font-semibold">Billing & Subscription</h2>
- <p className="text-sm text-muted-foreground mt-1">
- Manage your subscription and billing information
- </p>
- </div>
- <CreditCard className="h-6 w-6 text-muted-foreground" />
- </div>
-
- <div className="w-full flex flex-col justify-start gap-4">
- <div className="flex items-center justify-between">
- {hasSubscriptionReadStatusPermission && (
- <div className="flex items-center gap-3">
- <h3 className="font-medium">DrinksPOS Subscription</h3>
- <SubscriptionStatusBadge
- status={subscriptionStatus || "unknown"}
- className="font-semibold text-xs px-3 py-1.5 rounded-full border-0 shadow-sm"
- />
- </div>
- )}
-
- {hasSubscriptionReadPaymentLinkPermission && (
- <Button
- onClick={handlePaymentClick}
- disabled={isGeneratingPaymentLink}
- className="flex items-center gap-2"
- >
- {isGeneratingPaymentLink ? (
- <LoadingSpinner />
- ) : (
- <Receipt className="h-4 w-4" />
- )}
- {isGeneratingPaymentLink ? "Processing..." : "Manage Billing"}
- </Button>
- )}
- </div>
- </div>
- </div>
- );
-};
diff --git a/src/pages/Settings/Devices/DeviceManagementPanel.tsx b/src/pages/Settings/Devices/DeviceManagementPanel.tsx
index 09255b11..1d0ad901 100644
--- a/src/pages/Settings/Devices/DeviceManagementPanel.tsx
+++ b/src/pages/Settings/Devices/DeviceManagementPanel.tsx
@@ -1,22 +1,15 @@
-import {
- Button,
- Heading,
- HStack,
- Text,
- useToast,
- VStack,
-} from "@chakra-ui/react";
+import { Button, HStack, Heading, VStack, useToast } from "@chakra-ui/react";
import { Card, List } from "@tremor/react";
import { BackToSettingsButton } from "components/SettingsComponents/BackToSettingsButton";
import { useDocumentTitle } from "hooks/useDocumentTitle";
import { useEffect } from "react";
-import { EraseDatabaseButton } from "src/components/common/EraseDatabaseButton";
import { StyledPaginationControls } from "src/components/common/StyledPaginationControls/StyledPaginationControls";
import * as Sentry from "src/config/sentry/TransformitySentry";
import { useEntity } from "src/context/EntityProvider";
import { useGetRegistersForEntity } from "src/generated";
import { NumberParam, useQueryParam, withDefault } from "use-query-params";
import { useRequestCashDrawer } from "../../../components/CashDrawer";
+import { useRequestPoleDisplay } from "../../../components/PoleDisplay";
import { RegisterListItem } from "./RegisterListItem";
export type DeviceManagementPanelProps = {};
@@ -28,6 +21,7 @@ const DeviceManagementPanelInner: React.FC<DeviceManagementPanelProps> = () => {
const [entity] = useEntity();
const toast = useToast();
const requestCashDrawer = useRequestCashDrawer();
+ const requestPoleDisplay = useRequestPoleDisplay();
const { data: registers, error: registersError } = useGetRegistersForEntity(
entity?.id ?? 0,
{
@@ -75,6 +69,16 @@ const DeviceManagementPanelInner: React.FC<DeviceManagementPanelProps> = () => {
</Card>
<Card>
<HStack w="100%" justifyContent="flex-start">
+ <VStack
+ w="100%"
+ justifyContent="space-between"
+ alignItems="flex-start"
+ >
+ <Heading size="md">Pole Display</Heading>
+ <Button variant="outline" onClick={() => requestPoleDisplay()}>
+ Set up Pole Display
+ </Button>
+ </VStack>
<VStack
w="100%"
justifyContent="space-between"
@@ -87,24 +91,6 @@ const DeviceManagementPanelInner: React.FC<DeviceManagementPanelProps> = () => {
</VStack>
</HStack>
</Card>
- <Card>
- <VStack w="100%" alignItems="flex-start">
- <Heading size="md">Local Database</Heading>
- <Text fontSize="sm" color="gray.600" mb={4}>
- Manage the local database used for offline functionality and
- caching.
- </Text>
- <HStack w="100%" justifyContent="space-between" alignItems="center">
- <VStack alignItems="flex-start" spacing={1}>
- <Text fontWeight="medium">Database Status</Text>
- <Text fontSize="sm" color="gray.600">
- Active - storing transaction and product data
- </Text>
- </VStack>
- <EraseDatabaseButton />
- </HStack>
- </VStack>
- </Card>
</VStack>
);
};
diff --git a/src/pages/Settings/EntityConfiguration/EntityConfiguationPanel.tsx b/src/pages/Settings/EntityConfiguration/EntityConfiguationPanel.tsx
index 1d14d34b..234d2e06 100644
--- a/src/pages/Settings/EntityConfiguration/EntityConfiguationPanel.tsx
+++ b/src/pages/Settings/EntityConfiguration/EntityConfiguationPanel.tsx
@@ -53,6 +53,7 @@ type EntityConfigKeyWOFeeReport = Exclude<
| EntityConfigKey.CUSTOMER_FACING_DISPLAY_LOGO
| EntityConfigKey.TERMINAL_SCREEN_LOGO
| EntityConfigKey.ENABLE_SALE_HOTKEYS
+ | EntityConfigKey.SHOW_CASHIER_ON_RECEIPT
>;
const entityConfigMap: Record<
@@ -214,7 +215,7 @@ const entityConfigMap: Record<
[EntityConfigKey.ORDER_MULTIPLE_ITEMS_POPUP]: {
type: z.string().optional(),
label: "Order Multiple Items Popup By:",
- defaultValue: "ci_deposit_multiplier,asc",
+ defaultValue: "cohortItem.depositMultiplier,asc",
component: ({ field, defaultValue }) => {
const [selectedField, selectedDirection] = (
(field.value as string) || (defaultValue as string)
@@ -223,7 +224,7 @@ const entityConfigMap: Record<
const values = [
{
label: "Deposit Multiplier",
- value: "ci_deposit_multiplier",
+ value: "cohortItem.depositMultiplier",
},
{
label: "Price",
@@ -231,7 +232,7 @@ const entityConfigMap: Record<
},
{
label: "Name",
- value: "ci_name",
+ value: "cohortItem.name",
},
];
@@ -321,11 +322,6 @@ const entityConfigMap: Record<
label: "Print Receipt on Refund",
defaultValue: false,
},
- [EntityConfigKey.SHOW_CASHIER_ON_RECEIPT]: {
- type: z.boolean().optional(),
- label: "Show Cashier on Receipt",
- defaultValue: true,
- },
};
const EntityConfigurationFormSchema = z.object(
@@ -555,7 +551,6 @@ const Configuration = forwardRef<HTMLFormElement, ConfigurationProps>(
return null;
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[configKey, defaultValue],
);
diff --git a/src/pages/Settings/PriceLevels/PriceLevelsSettingsPanel.tsx b/src/pages/Settings/PriceLevels/PriceLevelsSettingsPanel.tsx
index f93a1dd2..17d77814 100644
--- a/src/pages/Settings/PriceLevels/PriceLevelsSettingsPanel.tsx
+++ b/src/pages/Settings/PriceLevels/PriceLevelsSettingsPanel.tsx
@@ -44,7 +44,6 @@ export const PriceLevelsSettingsPanel: React.FC = () => {
if (!isDialogOpen) {
void refetch();
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDialogOpen]);
const columns = [
diff --git a/src/pages/Settings/Roles/CreateUpdateRoleModal.tsx b/src/pages/Settings/Roles/CreateUpdateRoleModal.tsx
index fa2578e0..d6bb00bc 100644
--- a/src/pages/Settings/Roles/CreateUpdateRoleModal.tsx
+++ b/src/pages/Settings/Roles/CreateUpdateRoleModal.tsx
@@ -23,7 +23,7 @@ import { RoleForm } from "./RoleForm";
import { RoleManagementCategory } from "./RoleManagementCategory";
export type PermissionDescription = {
- permissionGroup: string[];
+ permission: string;
description: string;
displayName: string;
};
@@ -272,7 +272,6 @@ export const CreateUpdateRoleModal = ({
"shelftalker",
"audit_log",
"payment_option",
- "esub",
],
)
}
@@ -309,18 +308,18 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "entity",
permissionDescriptions: [
{
- permissionGroup: ["entity/*:remote"],
+ permission: "entity/*:remote",
description:
"Ability to access the system remotely (on a personal device).",
displayName: "Personal Access",
},
{
- permissionGroup: ["entity/*:manage", "entity/*:stream_health_check"],
+ permission: "entity/*:manage",
description: "Ability to update settings and roles for this store.",
displayName: "Manage Store",
},
{
- permissionGroup: ["entity/*:stats"],
+ permission: "entity/*:stats",
description: "Ability to view business metrics (Margin, Profit, etc.).",
displayName: "View Stats",
},
@@ -331,27 +330,27 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "user",
permissionDescriptions: [
{
- permissionGroup: ["user/*:read"],
+ permission: "user/*:read",
description: "Ability to read users.",
displayName: "Read",
},
{
- permissionGroup: ["user/*:manage"],
+ permission: "user/*:manage",
description: "Ability to manage users.",
displayName: "Manage",
},
{
- permissionGroup: ["user/*:change-pin"],
+ permission: "user/*:change-pin",
description: "Ability to change other users' pins.",
displayName: "Change Pin",
},
{
- permissionGroup: ["user/*:delete"],
+ permission: "user/*:delete",
description: "Ability to remove users.",
displayName: "Delete",
},
{
- permissionGroup: ["user/*:invite"],
+ permission: "user/*:invite",
description: "Ability to add new users.",
displayName: "Add",
},
@@ -362,49 +361,49 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "item",
permissionDescriptions: [
{
- permissionGroup: ["item/*:read"],
+ permission: "item/*:read",
description: "Ability to read items.",
displayName: "Read",
},
{
- permissionGroup: ["item/*:manage-prices"],
+ permission: "item/*:manage-prices",
description: "Ability to manage item prices.",
displayName: "Manage Prices",
},
{
- permissionGroup: ["item/*:manage-inventory-pricing"],
+ permission: "item/*:manage-inventory-pricing",
description:
"Ability to manage store-specific item details (quantity, costs, etc.).",
displayName: "Manage Store Fields",
},
{
- permissionGroup: ["item/*:manage-vendors"],
+ permission: "item/*:manage-vendors",
description: "Ability to manage item vendors",
displayName: "Manage Item Vendors",
},
{
- permissionGroup: ["item/*:manage-item-details"],
+ permission: "item/*:manage-item-details",
description:
"Ability to manage item details (name, department, case size, pack size, deposits, etc.).",
displayName: "Manage Shared Fields",
},
{
- permissionGroup: ["item/*:delete"],
+ permission: "item/*:delete",
description: "Ability to delete items.",
displayName: "Delete",
},
{
- permissionGroup: ["item/*:exclusive"],
+ permission: "item/*:exclusive",
description: "Ability to manage exclusive items.",
displayName: "Exclusive",
},
{
- permissionGroup: ["item/*:stats"],
+ permission: "item/*:stats",
description: "Ability to see cost, profit stats per item.",
displayName: "Statistics",
},
{
- permissionGroup: ["item/*:barcode"],
+ permission: "item/*:barcode",
description: "Ability to manage item barcodes",
displayName: "Barcode",
},
@@ -415,17 +414,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "civin",
permissionDescriptions: [
{
- permissionGroup: ["civin/*:create"],
+ permission: "civin/*:create",
description: "Ability to create item vintage",
displayName: "Create Vintage",
},
{
- permissionGroup: ["civin/*:update"],
+ permission: "civin/*:update",
description: "Ability to update item vintage",
displayName: "Update Vintage",
},
{
- permissionGroup: ["civin/*:delete"],
+ permission: "civin/*:delete",
description: "Ability to delete item vintage",
displayName: "Delete Vintage",
},
@@ -436,17 +435,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "item_list",
permissionDescriptions: [
{
- permissionGroup: ["item_list/*:read"],
+ permission: "item_list/*:read",
description: "Ability to read item lists.",
displayName: "Read",
},
{
- permissionGroup: ["item_list/*:manage"],
+ permission: "item_list/*:manage",
description: "Ability to manage item lists.",
displayName: "Manage",
},
{
- permissionGroup: ["item_list/*:delete"],
+ permission: "item_list/*:delete",
description: "Ability to delete item lists.",
displayName: "Delete",
},
@@ -457,68 +456,68 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "pos",
permissionDescriptions: [
{
- permissionGroup: ["pos:discount-total"],
+ permission: "pos:discount-total",
description: "Ability to apply discounts for the entire order.",
displayName: "Discount Total",
},
{
- permissionGroup: ["pos:discount-line-item"],
+ permission: "pos:discount-line-item",
description: "Ability to apply discounts for individual items.",
displayName: "Discount Line Item",
},
{
- permissionGroup: ["pos:edit-price"],
+ permission: "pos:edit-price",
description: "Ability to edit the price of an item on the sale screen.",
displayName: "Edit Price",
},
{
- permissionGroup: ["pos:payout"],
+ permission: "pos:payout",
description: "Ability to do a payout on the sales screen.",
displayName: "Payout",
},
{
- permissionGroup: ["pos:sell-negative-quantity"],
+ permission: "pos:sell-negative-quantity",
description: "Ability to sell negative quantity items.",
displayName: "Sell Negative Quantity",
},
{
- permissionGroup: ["pos:change-sales-channel"],
+ permission: "pos:change-sales-channel",
description: "Ability to change the sales channel of a sale.",
displayName: "Change Sales Channel",
},
{
- permissionGroup: ["pos:remove-item"],
+ permission: "pos:remove-item",
description: "Ability to remove items from cart.",
displayName: "Remove Item",
},
{
- permissionGroup: ["pos:increase-quantity"],
+ permission: "pos:increase-quantity",
description: "Ability to increase the quantity of an item in cart.",
displayName: "Increase Quantity",
},
{
- permissionGroup: ["pos:decrease-quantity"],
+ permission: "pos:decrease-quantity",
description: "Ability to decrease the quantity of an item in cart.",
displayName: "Decrease Quantity",
},
{
- permissionGroup: ["pos:add-from-search"],
+ permission: "pos:add-from-search",
description:
"Ability to add items to a sale by text based search (i.e. without scanning a barcode).",
displayName: "Add from Search",
},
{
- permissionGroup: ["pos:tax-exempt"],
+ permission: "pos:tax-exempt",
description: "Ability to apply tax exemption on sales.",
displayName: "Tax Exempt",
},
{
- permissionGroup: ["pos:reset-cart"],
+ permission: "pos:reset-cart",
description: "Ability to reset cart on the sales screen",
displayName: "Reset Cart",
},
{
- permissionGroup: ["pos:new-item"],
+ permission: "pos:new-item",
description: "Ability to use the New Item button on the sales screen",
displayName: "New Item",
},
@@ -529,7 +528,7 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "price_level",
permissionDescriptions: [
{
- permissionGroup: ["price_level/*:manage"],
+ permission: "price_level/*:manage",
description: "Ability to manage price levels.",
displayName: "Manage",
},
@@ -540,18 +539,13 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "saleschannel",
permissionDescriptions: [
{
- permissionGroup: ["saleschannel/*:read", "escpm/*:read"],
- description: "Ability to read sales channels and ESCPM data.",
+ permission: "saleschannel/*:read",
+ description: "Ability to read sales channels.",
displayName: "Read",
},
{
- permissionGroup: [
- "saleschannel/*:manage",
- "escpm/*:create",
- "escpm/*:update",
- "escpm/*:delete",
- ],
- description: "Ability to manage sales channels and ESCPM data.",
+ permission: "saleschannel/*:manage",
+ description: "Ability to manage sales channels.",
displayName: "Manage",
},
],
@@ -561,12 +555,12 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "department",
permissionDescriptions: [
{
- permissionGroup: ["department/*:manage-group"],
+ permission: "department/*:manage-group",
description: "Ability to manage department groups.",
displayName: "Manage Group",
},
{
- permissionGroup: ["department/*:manage-department"],
+ permission: "department/*:manage-department",
description: "Ability to manage departments.",
displayName: "Manage Department",
},
@@ -577,22 +571,22 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "transaction",
permissionDescriptions: [
{
- permissionGroup: ["transaction/*:read"],
+ permission: "transaction/*:read",
description: "Ability to read transactions.",
displayName: "Read",
},
{
- permissionGroup: ["transaction/*:search"],
+ permission: "transaction/*:search",
description: "Ability to search transactions.",
displayName: "Search",
},
{
- permissionGroup: ["transaction/*:void"],
- description: "Ability to refund transactions.",
- displayName: "Refund",
+ permission: "transaction/*:void",
+ description: "Ability to void transactions.",
+ displayName: "Void",
},
{
- permissionGroup: ["transaction/*:read-shift-totals"],
+ permission: "transaction/*:read-shift-totals",
description: "Ability to read shift totals",
displayName: "Read Shift Totals",
},
@@ -603,17 +597,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "promotion",
permissionDescriptions: [
{
- permissionGroup: ["promotion/*:read"],
+ permission: "promotion/*:read",
description: "Ability to read promotions.",
displayName: "Read",
},
{
- permissionGroup: ["promotion/*:create"],
+ permission: "promotion/*:create",
description: "Ability to create promotions.",
displayName: "Create",
},
{
- permissionGroup: ["promotion/*:manage"],
+ permission: "promotion/*:manage",
description: "Ability to manage promotions.",
displayName: "Manage",
},
@@ -624,17 +618,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "invoice",
permissionDescriptions: [
{
- permissionGroup: ["invoice/*:read"],
+ permission: "invoice/*:read",
description: "Ability to read invoices.",
displayName: "Read",
},
{
- permissionGroup: ["invoice/*:draft"],
+ permission: "invoice/*:draft",
description: "Ability to draft invoices.",
displayName: "Draft",
},
{
- permissionGroup: ["invoice/*:receive"],
+ permission: "invoice/*:receive",
description: "Ability to set prices, receive invoices.",
displayName: "Receive",
},
@@ -645,17 +639,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "purchaseorder",
permissionDescriptions: [
{
- permissionGroup: ["purchaseorder/*:read"],
+ permission: "purchaseorder/*:read",
description: "Open and view purchase orders.",
displayName: "Read",
},
{
- permissionGroup: ["purchaseorder/*:draft"],
+ permission: "purchaseorder/*:draft",
description: "Ability to draft purchase orders.",
displayName: "Draft",
},
{
- permissionGroup: ["purchaseorder/*:receive"],
+ permission: "purchaseorder/*:receive",
description: "Ability to receive purchase orders.",
displayName: "Receive",
},
@@ -666,32 +660,32 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "vendor",
permissionDescriptions: [
{
- permissionGroup: ["vendor/*:read"],
+ permission: "vendor/*:read",
description: "Ability to see vendors.",
displayName: "See Vendors",
},
{
- permissionGroup: ["vendor/*:exclusive"],
+ permission: "vendor/*:exclusive",
description: "Ability to see exclusive vendors.",
displayName: "See Exclusive Vendors",
},
{
- permissionGroup: ["vendor/*:manage-store-vendors"],
+ permission: "vendor/*:manage-store-vendors",
description: "Ability to manage vendors at the store level.",
displayName: "Manage Store Vendors",
},
{
- permissionGroup: ["vendor/*:manage-cohort-vendors"],
+ permission: "vendor/*:manage-cohort-vendors",
description: "Ability to manage vendors across the group of stores.",
displayName: "Manage Vendors",
},
{
- permissionGroup: ["vendor/*:read-vendor-groups"],
+ permission: "vendor/*:read-vendor-groups",
description: "Ability to read vendor groups.",
displayName: "Read Vendor Groups",
},
{
- permissionGroup: ["vendor/*:manage-vendor-groups"],
+ permission: "vendor/*:manage-vendor-groups",
description: "Ability to manage vendor groups.",
displayName: "Manage Vendor Groups",
},
@@ -702,27 +696,27 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "loyalty",
permissionDescriptions: [
{
- permissionGroup: ["loyalty/*:read"],
+ permission: "loyalty/*:read",
description: "Ability to read loyalty program settings.",
displayName: "Read",
},
{
- permissionGroup: ["loyalty/*:manage"],
+ permission: "loyalty/*:manage",
description: "Ability to manage loyalty program settings.",
displayName: "Manage",
},
{
- permissionGroup: ["loyalty/*:entity-stats"],
+ permission: "loyalty/*:entity-stats",
description: "Ability to view entity statistics.",
displayName: "View Entity Stats",
},
{
- permissionGroup: ["loyalty/*:manageCustomerInformation"],
+ permission: "loyalty/*:manageCustomerInformation",
description: "Ability to manage customer basic info",
displayName: "Manage Basic Info",
},
{
- permissionGroup: ["loyalty/*:manageCustomerPricingInfo"],
+ permission: "loyalty/*:manageCustomerPricingInfo",
description: "Ability to manage customer advanced info",
displayName: "Manage Advanced Info",
},
@@ -733,27 +727,27 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "campaign",
permissionDescriptions: [
{
- permissionGroup: ["campaign/*:read"],
+ permission: "campaign/*:read",
description: "Ability to read campaigns.",
displayName: "Read",
},
{
- permissionGroup: ["campaign/*:update"],
+ permission: "campaign/*:update",
description: "Ability to update campaigns.",
displayName: "Update",
},
{
- permissionGroup: ["campaign/*:create"],
+ permission: "campaign/*:create",
description: "Ability to create campaigns.",
displayName: "Create",
},
{
- permissionGroup: ["campaign/*:trigger"],
+ permission: "campaign/*:trigger",
description: "Ability to trigger campaigns.",
displayName: "Trigger",
},
{
- permissionGroup: ["campaign/*:delete"],
+ permission: "campaign/*:delete",
description: "Ability to delete campaigns.",
displayName: "Delete",
},
@@ -764,22 +758,22 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "customerhouseaccount",
permissionDescriptions: [
{
- permissionGroup: ["customerhouseaccount/*:read"],
+ permission: "customerhouseaccount/*:read",
description: "Ability to read customer house accounts.",
displayName: "Read",
},
{
- permissionGroup: ["customerhouseaccount/*:create"],
+ permission: "customerhouseaccount/*:create",
description: "Ability to create customer house accounts.",
displayName: "Create",
},
{
- permissionGroup: ["customerhouseaccount/*:update"],
+ permission: "customerhouseaccount/*:update",
description: "Ability to update customer house accounts once created.",
displayName: "Update",
},
{
- permissionGroup: ["customerhouseaccount/*:update-credit-limit"],
+ permission: "customerhouseaccount/*:update-credit-limit",
description: "Ability to update credit limits on a house account.",
displayName: "Update Credit Limit",
},
@@ -790,17 +784,17 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "inventory_transfers",
permissionDescriptions: [
{
- permissionGroup: ["inventory_transfers/*:read"],
+ permission: "inventory_transfers/*:read",
description: "Open and view inventory transfers.",
displayName: "Read",
},
{
- permissionGroup: ["inventory_transfers/*:manage"],
+ permission: "inventory_transfers/*:manage",
description: "Ability to manage inventory transfers.",
displayName: "Manage",
},
{
- permissionGroup: ["inventory_transfers/*:merge"],
+ permission: "inventory_transfers/*:merge",
description: "Ability to merge inventory transfers.",
displayName: "Merge",
},
@@ -811,22 +805,22 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "inventory_count",
permissionDescriptions: [
{
- permissionGroup: ["inventory_count/*:read"],
+ permission: "inventory_count/*:read",
description: "Open and view inventory counts.",
displayName: "Read",
},
{
- permissionGroup: ["inventory_count/*:count"],
+ permission: "inventory_count/*:count",
description: "Ability to count items in an inventory count.",
displayName: "Count",
},
{
- permissionGroup: ["inventory_count/*:complete-rotate"],
+ permission: "inventory_count/*:complete-rotate",
description: "Ability to complete inventory rotational counts",
displayName: "Complete rotational count",
},
{
- permissionGroup: ["inventory_count/*:complete-full"],
+ permission: "inventory_count/*:complete-full",
description: "Ability to complete inventory full store count",
displayName: "Complete full store count",
},
@@ -837,12 +831,12 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "shelftalker",
permissionDescriptions: [
{
- permissionGroup: ["shelftalker/*:manage-task"],
+ permission: "shelftalker/*:manage-task",
description: "Ability to create and manage shelf talker tasks.",
displayName: "Manage Tasks",
},
{
- permissionGroup: ["shelftalker/*:manage-preset"],
+ permission: "shelftalker/*:manage-preset",
description: "Ability to manage shelf talker presets (templates).",
displayName: "Manage Presets",
},
@@ -853,38 +847,38 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "report",
permissionDescriptions: [
{
- permissionGroup: ["report/transactionReports:read"],
+ permission: "report/transactionReports:read",
description: "Ability to read transaction reports.",
displayName: "Transaction Reports",
},
{
- permissionGroup: ["report/paymentsProcessor:read"],
+ permission: "report/paymentsProcessor:read",
description:
"Ability to read payment processor reports, including ACH payouts.",
displayName: "Payment Processor Reports",
},
{
- permissionGroup: ["report/itemReports:read"],
+ permission: "report/itemReports:read",
description: "Ability to read item reports.",
displayName: "Item Reports",
},
{
- permissionGroup: ["report/invoiceReports:read"],
+ permission: "report/invoiceReports:read",
description: "Ability to read invoice reports.",
displayName: "Invoice Reports",
},
{
- permissionGroup: ["report/inventoryReport:read"],
+ permission: "report/inventoryReport:read",
description: "Ability to read inventory reports.",
displayName: "Inventory Report",
},
{
- permissionGroup: ["report/totalsReport:read"],
+ permission: "report/totalsReport:read",
description: "Ability to read totals reports.",
displayName: "Totals Report",
},
{
- permissionGroup: ["report/todaysTotals:read"],
+ permission: "report/todaysTotals:read",
description: "Ability to read todays total report.",
displayName: "Today's Totals",
},
@@ -895,22 +889,22 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "register",
permissionDescriptions: [
{
- permissionGroup: ["register/*:open"],
+ permission: "register/*:open",
description: "Ability to open a register.",
displayName: "Open",
},
{
- permissionGroup: ["register/*:change"],
+ permission: "register/*:change",
description: "Ability to change a register.",
displayName: "Change",
},
{
- permissionGroup: ["register/*:close"],
+ permission: "register/*:close",
description: "Ability to close a register.",
displayName: "Close",
},
{
- permissionGroup: ["register/*:pop"],
+ permission: "register/*:pop",
description: "Ability to pop the cash drawer.",
displayName: "Pop",
},
@@ -921,90 +915,68 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "payment_option",
permissionDescriptions: [
{
- permissionGroup: ["payment_option/credit_card:use"],
+ permission: "payment_option/credit_card:use",
description: "Ability to take credit card payments.",
displayName: "Credit Card",
},
{
- permissionGroup: ["payment_option/cash:use"],
+ permission: "payment_option/cash:use",
description: "Ability to take cash payments.",
displayName: "Cash",
},
{
- permissionGroup: ["payment_option/manual_credit_card:use"],
+ permission: "payment_option/manual_credit_card:use",
description: "Ability to take manual credit card payments.",
displayName: "Manual Credit Card",
},
{
- permissionGroup: ["payment_option/check:use"],
+ permission: "payment_option/check:use",
description: "Ability to take check payments.",
displayName: "Check",
},
{
- permissionGroup: ["payment_option/gift_card:use"],
+ permission: "payment_option/gift_card:use",
description: "Ability to take gift card payments.",
displayName: "Gift Card",
},
{
- permissionGroup: ["payment_option/points:use"],
+ permission: "payment_option/points:use",
description: "Ability to take loyalty points as payments.",
displayName: "Loyalty Points",
},
{
- permissionGroup: ["payment_option/pay_later:use"],
+ permission: "payment_option/pay_later:use",
description: "Ability to take pay later payments.",
displayName: "Pay Later",
},
{
- permissionGroup: ["payment_option/multiple:use"],
+ permission: "payment_option/multiple:use",
description: "Ability to take multiple payments.",
displayName: "Multiple",
},
{
- permissionGroup: ["payment_option/other:use"],
+ permission: "payment_option/other:use",
description: "Ability to take other payment methods.",
displayName: "Other",
},
{
- permissionGroup: ["payment_option/house_account:use"],
+ permission: "payment_option/house_account:use",
description: "Ability to take house account payments.",
displayName: "House Account",
},
{
- permissionGroup: ["payment_option/payment_link:use"],
+ permission: "payment_option/payment_link:use",
description: "Ability to create and take payment links as payments.",
displayName: "Payment Link",
},
],
},
- {
- title: "Fulfillment",
- resourceType: "fulfillment",
- permissionDescriptions: [
- {
- permissionGroup: ["fulfillment/*:update"],
- description: "Ability to update fulfillment.",
- displayName: "Update",
- },
- ],
- },
- {
- title: "Order Item Decisions",
- resourceType: "orderitemdecision",
- permissionDescriptions: [
- {
- permissionGroup: ["orderitemdecision/*:update-status"],
- description: "Ability to accept or reject order item decisions.",
- displayName: "Update Status",
- },
- ],
- },
{
title: "Audit Log",
resourceType: "audit_log",
permissionDescriptions: [
{
- permissionGroup: ["audit_log/*:read"],
+ permission: "audit_log/*:read",
description: "Ability to see audit log.",
displayName: "See Audit Log",
},
@@ -1015,28 +987,11 @@ const permissionSettingsDescriptions: PermissionCategory[] = [
resourceType: "label",
permissionDescriptions: [
{
- permissionGroup: ["label/*:manage"],
+ permission: "label/*:manage",
description:
"Ability to create, import, and delete label printer templates.",
displayName: "Manage",
},
],
},
- {
- title: "Billing",
- resourceType: "esub",
- permissionDescriptions: [
- {
- permissionGroup: ["esub/*:read_subscription_status"],
- description: "Ability to view subscription status.",
- displayName: "Read Subscription Status",
- },
- {
- permissionGroup: ["esub/*:generate_subscription_link"],
- description:
- "Ability to access payment links for subscription billing.",
- displayName: "Generate Subscription Payment Link",
- },
- ],
- },
];
diff --git a/src/pages/Settings/Roles/RoleManagementCategory.tsx b/src/pages/Settings/Roles/RoleManagementCategory.tsx
index 36b35bb6..54a22559 100644
--- a/src/pages/Settings/Roles/RoleManagementCategory.tsx
+++ b/src/pages/Settings/Roles/RoleManagementCategory.tsx
@@ -7,7 +7,12 @@ import {
import { ChevronDownIcon } from "@radix-ui/react-icons";
import { useEffect } from "react";
import { useFormContext, useWatch } from "react-hook-form";
-import { PermissionDescription } from "./CreateUpdateRoleModal";
+
+type PermissionDescription = {
+ permission: string;
+ description: string;
+ displayName: string;
+};
export type RoleManagementCategoryProps = {
title: string;
@@ -30,41 +35,20 @@ export const RoleManagementCategory: React.FC<RoleManagementCategoryProps> = ({
const { register, setValue, watch, getValues, trigger } = useFormContext();
const value = useWatch({ name: "value" });
- // Helper function to get all permissions from a permission description
- const getPermissionGroup = (
- permissionDesc: PermissionDescription,
- ): string[] => {
- return permissionDesc.permissionGroup;
- };
-
- // Helper function to check if all permissions from a description are selected
- const arePermissionsSelected = (
- permissionDesc: PermissionDescription,
- ): boolean => {
- const permissions = getPermissionGroup(permissionDesc);
- return permissions.every((perm) => value?.includes(perm));
- };
-
- // Helper function to get all permissions from all descriptions
- const getAllPermissions = (): string[] => {
- return permissionDescriptions.flatMap(getPermissionGroup);
- };
-
useEffect(() => {
- const allPermissions = getAllPermissions();
+ const permissionList = permissionDescriptions.map((row) => row.permission);
// If "All" checkbox is checked, remove all other checkboxes
if (
value?.includes(`${resourceType}/*:*`) &&
- allPermissions.some((permission) => value.includes(permission))
+ permissionList.some((permission) => value.includes(permission))
) {
setValue("value", [
...value?.filter(
- (permission: string) => !allPermissions.includes(permission),
+ (permission: string) => !permissionList.includes(permission),
),
]);
void trigger("value");
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [permissionDescriptions, resourceType, setValue, trigger, value]);
return (
@@ -90,7 +74,7 @@ export const RoleManagementCategory: React.FC<RoleManagementCategoryProps> = ({
value?.includes(`${resourceType}/*:*`)
? true
: permissionDescriptions.some((row) =>
- arePermissionsSelected(row),
+ value?.includes(row.permission),
)
? "indeterminate"
: false
@@ -121,39 +105,26 @@ export const RoleManagementCategory: React.FC<RoleManagementCategoryProps> = ({
<CollapsibleContent className="p-4">
<div className="grid grid-cols-2 gap-4">
{permissionDescriptions.map((entry) => {
- const {
- permissionGroup: permissionGroup,
- description,
- displayName,
- } = entry;
- const permissions = getPermissionGroup(entry);
- const key = Array.isArray(permissionGroup)
- ? permissionGroup.join(",")
- : permissionGroup;
-
+ const { permission, description, displayName } = entry;
return (
- <div key={key} className="flex items-start gap-2 flex-1">
+ <div key={permission} className="flex items-start gap-2 flex-1">
<Checkbox
checked={
value?.includes(`${resourceType}/*:*`) ||
- arePermissionsSelected(entry)
+ value?.includes(permission)
}
disabled={value?.includes(`${resourceType}/*:*`)}
- value={permissions[0]} // Use first permission as the value for the checkbox
+ value={permission}
{...register("value")}
className="mt-1"
onCheckedChange={(checked) => {
const currentValue = getValues("value");
if (checked) {
- // Add all permissions in the bundle
- setValue("value", [...currentValue, ...permissions]);
+ setValue("value", [...currentValue, permission]);
} else {
- // Remove all permissions in the bundle
setValue(
"value",
- currentValue.filter(
- (v: string) => !permissions.includes(v),
- ),
+ currentValue.filter((v: string) => v !== permission),
);
}
void trigger("value");
diff --git a/src/pages/Settings/SalesChannels/EditSalesChannelPage.tsx b/src/pages/Settings/SalesChannels/EditSalesChannelPage.tsx
deleted file mode 100644
index 03c26b86..00000000
--- a/src/pages/Settings/SalesChannels/EditSalesChannelPage.tsx
+++ /dev/null
@@ -1,273 +0,0 @@
-import { Heading, Text } from "@chakra-ui/react";
-import { DefaultLayoutWithNavbar } from "components/layouts/DefaultLayoutWithNavbar";
-import { PageWithSidebar } from "components/layouts/PageWithSidebar";
-import { PaymentMethodManager } from "components/SalesChannels/PaymentMethodManager";
-import { SalesChannelBasicInfoStep } from "components/SalesChannels/SalesChannelBasicInfoStep";
-import { Button } from "components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "components/ui/card";
-import { LoadingSpinner } from "components/ui/loading-spinner";
-import { captureException } from "config/sentry/TransformitySentry";
-import { useEntitySelected } from "context/EntityProvider";
-import { useDocumentTitle } from "hooks/useDocumentTitle";
-import { SalesChannelFormData } from "hooks/useSalesChannelWizard";
-import { ChevronLeft } from "lucide-react";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
-import { useForm } from "react-hook-form";
-import { useNavigate, useParams } from "react-router-dom";
-import { toast } from "sonner";
-import {
- useGetEntitySalesChannelById,
- useListSalesChannelDepartments,
- useUpsertEntitySalesChannel,
-} from "src/spring-generated";
-import { extractAxios400ErrorMessage } from "utils/errors";
-
-export const EditSalesChannelPage: React.FC = () => {
- const { id } = useParams<{ id: string }>();
- const navigate = useNavigate();
- const [entity] = useEntitySelected();
- const [selectedDepartments, setSelectedDepartments] = useState<number[]>([]);
-
- const salesChannelId = parseInt(id || "0");
-
- useDocumentTitle(`Edit Sales Channel`);
-
- // Fetch sales channel data
- const {
- data: salesChannel,
- isLoading: isLoadingSalesChannel,
- error: salesChannelError,
- } = useGetEntitySalesChannelById(salesChannelId, {
- query: {
- enabled: !!salesChannelId && salesChannelId > 0,
- },
- });
-
- // Fetch sales channel departments
- const {
- data: entitySalesChannelDepartments,
- isFetching: isLoadingSalesChannelDepartments,
- } = useListSalesChannelDepartments(salesChannelId, {
- query: {
- enabled: !!salesChannelId && salesChannelId > 0,
- },
- });
-
- const defaultValues = useMemo(() => {
- if (!salesChannel) {
- return {
- entityId: entity?.id,
- name: "",
- salesChannelTypeId: 1,
- active: false,
- taxable: false,
- autoAddNewDepartments: false,
- allowNegativeInventory: false,
- departmentIds: [],
- paymentMethods: [],
- };
- }
-
- return {
- ...salesChannel,
- departmentIds: [],
- paymentMethods: [],
- };
- }, [salesChannel, entity?.id]);
-
- const form = useForm<SalesChannelFormData>({
- defaultValues,
- });
-
- const { mutateAsync: upsertSalesChannel, isPending: isSaving } =
- useUpsertEntitySalesChannel({
- mutation: {
- onSuccess: () => {
- toast.success("Sales channel updated successfully");
- },
- onError: (error) => {
- console.log("Error updating sales channel:", error);
- toast.error(
- "Failed to update sales channel: " +
- extractAxios400ErrorMessage(error),
- );
- console.error("Error updating sales channel:", error);
- captureException(error);
- },
- },
- });
-
- // Populate form when data loads
- useEffect(() => {
- if (salesChannel) {
- if (entitySalesChannelDepartments) {
- const departmentIds = entitySalesChannelDepartments.map(
- (department) => department.id.departmentId,
- );
- form.reset({
- ...defaultValues,
- departmentIds,
- });
- setSelectedDepartments(departmentIds);
- } else {
- form.reset(defaultValues);
- setSelectedDepartments(defaultValues.departmentIds);
- }
- }
- }, [salesChannel, entitySalesChannelDepartments, defaultValues, form]);
-
- // Update selectedDepartments when entitySalesChannelDepartments changes
- useEffect(() => {
- if (entitySalesChannelDepartments) {
- const departmentIds = entitySalesChannelDepartments.map(
- (department) => department.id.departmentId,
- );
- console.log("Setting departments:", departmentIds);
- setSelectedDepartments(departmentIds);
- form.setValue("departmentIds", departmentIds);
- }
- }, [entitySalesChannelDepartments, form]);
-
- const handleBasicInfoSave = useCallback(async () => {
- const values = form.getValues();
-
- try {
- await upsertSalesChannel({
- data: {
- ...values,
- id: salesChannelId,
- },
- });
- } catch (error) {
- // Error handling is done in the mutation
- }
- }, [form, upsertSalesChannel, salesChannelId]);
-
- // Define sidebar items for the sales channel settings
- const sidebarItems = useMemo(
- () => [
- {
- id: "basic-info",
- header: "Basic Information",
- content: (
- <Card>
- <CardHeader>
- <CardTitle>Basic Information</CardTitle>
- </CardHeader>
- <CardContent className="space-y-6">
- <SalesChannelBasicInfoStep
- form={form}
- selectedDepartments={selectedDepartments}
- setSelectedDepartments={setSelectedDepartments}
- />
-
- <div className="flex justify-end pt-4 border-t">
- <Button
- onClick={handleBasicInfoSave}
- disabled={isSaving}
- className="min-w-[120px]"
- >
- {isSaving ? "Saving..." : "Save Changes"}
- </Button>
- </div>
- </CardContent>
- </Card>
- ),
- },
- {
- id: "payment-methods",
- header: "Payment Methods",
- content: (
- <Card>
- <CardHeader>
- <CardTitle>Payment Methods</CardTitle>
- </CardHeader>
- <CardContent>
- <PaymentMethodManager
- form={form}
- salesChannelId={salesChannelId}
- />
- </CardContent>
- </Card>
- ),
- },
- ],
- [
- form,
- selectedDepartments,
- setSelectedDepartments,
- isSaving,
- salesChannelId,
- handleBasicInfoSave,
- ],
- );
-
- if (isLoadingSalesChannel || isLoadingSalesChannelDepartments) {
- return (
- <DefaultLayoutWithNavbar pageTitle="Edit Sales Channel">
- <div className="flex items-center justify-center min-h-[400px]">
- <LoadingSpinner />
- </div>
- </DefaultLayoutWithNavbar>
- );
- }
-
- if (salesChannelError || !salesChannel) {
- return (
- <DefaultLayoutWithNavbar pageTitle="Edit Sales Channel">
- <div className="max-w-4xl mx-auto p-6">
- <div className="text-center py-8">
- <h2 className="text-xl font-semibold text-gray-900 mb-2">
- Sales Channel Not Found
- </h2>
- <p className="text-gray-600 mb-4">
- The sales channel you're looking for doesn't exist or you don't
- have permission to view it.
- </p>
- <Button
- onClick={() =>
- navigate("/settings/sales-channels?tab=saleschannels")
- }
- >
- Back to Sales Channels
- </Button>
- </div>
- </div>
- </DefaultLayoutWithNavbar>
- );
- }
-
- return (
- <DefaultLayoutWithNavbar pageTitle="Edit Sales Channel">
- <div className="w-5/6 p-6">
- {/* Header */}
- <div className="mb-6">
- <div className="flex items-center gap-4 mb-4">
- <Button
- variant="ghost"
- size="sm"
- onClick={() =>
- navigate("/settings/sales-channels?tab=saleschannels")
- }
- className="flex items-center gap-2"
- >
- <ChevronLeft className="h-4 w-4" />
- Back to Sales Channels
- </Button>
- <div>
- <Heading fontSize="2xl">{salesChannel.name}</Heading>
- <Text fontSize="sm" fontWeight="normal">
- Sales Channel Settings
- </Text>
- </div>
- </div>
- </div>
-
- {/* Tabs */}
- <PageWithSidebar orientation="horizontal" sidebarItems={sidebarItems} />
- </div>
- </DefaultLayoutWithNavbar>
- );
-};
-
-export default EditSalesChannelPage;
diff --git a/src/pages/Settings/SalesChannels/SalesChannelSettingsPanel.tsx b/src/pages/Settings/SalesChannels/SalesChannelSettingsPanel.tsx
deleted file mode 100644
index 2837c2dd..00000000
--- a/src/pages/Settings/SalesChannels/SalesChannelSettingsPanel.tsx
+++ /dev/null
@@ -1,227 +0,0 @@
-import { useDisclosure, useToast } from "@chakra-ui/react";
-import { captureException } from "@sentry/react";
-import { useQueryClient } from "@tanstack/react-query";
-import { StyledPaginationControls } from "components/common/StyledPaginationControls/StyledPaginationControls";
-import { DeleteButtonWithWarning } from "components/DeleteButtonWithWarning";
-import { CreateSalesChannelWizardV2 } from "components/SalesChannels/CreateSalesChannelWizardV2";
-import { SalesChannelBadge } from "components/SalesChannels/SalesChannelBadge";
-import { SettingsBlock } from "components/SettingsComponents/SettingsBlock";
-import { Badge } from "components/ui/badge";
-import { Button } from "components/ui/button";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "components/ui/tooltip";
-import { useEntitySelected } from "context/EntityProvider";
-import { useDocumentTitle } from "hooks/useDocumentTitle";
-import { AlertCircle, PlusIcon } from "lucide-react";
-import { useNavigate } from "react-router-dom";
-import {
- ApiPageEntitySalesChannel,
- useDeleteSalesChannel,
- useListSalesChannels,
-} from "src/spring-generated";
-import { NumberParam, useQueryParams, withDefault } from "use-query-params";
-import { isAxios400 } from "utils/errors";
-
-type SalesChannelSettingsPanelProps = {};
-
-export const SalesChannelSettingsPanel: React.FC<
- SalesChannelSettingsPanelProps
-> = () => {
- useDocumentTitle("Settings - Sales Channel");
- const [entity] = useEntitySelected();
- const queryClient = useQueryClient();
- const navigate = useNavigate();
- const [{ page }] = useQueryParams({
- page: withDefault(NumberParam, 1),
- });
- const { data: salesChannels, queryKey } = useListSalesChannels({
- entityIds: [entity.id],
- page: page - 1,
- size: 30,
- });
-
- // Create disclosure
- const createDisclosure = useDisclosure();
-
- // Check for sales channels without default payment methods
- const channelsWithoutDefaultPaymentMethod =
- salesChannels?.content?.filter(
- (channel) => !channel.defaultPaymentMethodId,
- ) || [];
-
- return (
- <SettingsBlock
- flexGrow={1}
- header={
- <div className="w-full flex flex-row justify-between">
- <h1 className="text-2xl font-bold">Sales Channels</h1>
- <Button onClick={createDisclosure.onOpen}>
- <PlusIcon className="w-4 h-4 mr-2" />
- New Sales Channel
- </Button>
- </div>
- }
- >
- <ul className="space-y-4 w-full flex-grow flex flex-col">
- {salesChannels?.content?.map((channel) => {
- const hasNoDefaultPaymentMethod = !channel.defaultPaymentMethodId;
-
- return (
- <li
- key={channel.id}
- className={`flex items-center border-b justify-between p-2 rounded-md ${
- hasNoDefaultPaymentMethod
- ? "border-orange-200 bg-orange-50"
- : ""
- }`}
- >
- <div>
- <div className="flex flex-row items-center gap-2">
- <h3 className="font-semibold">{channel.name}</h3>
- <SalesChannelBadge salesChannel={channel} />
- {hasNoDefaultPaymentMethod && (
- <Badge
- variant="secondary"
- className="text-xs text-orange-700 bg-orange-100 border-orange-200"
- >
- <AlertCircle className="w-3 h-3 mr-1" />
- No Default Payment Method
- </Badge>
- )}
- </div>
- {channel.accountId && (
- <p className="text-sm text-gray-600">
- Account ID: {channel.accountId}
- </p>
- )}
- {hasNoDefaultPaymentMethod && (
- <p className="text-sm text-orange-600 mt-1">
- This sales channel needs a default payment method to work
- properly. Please edit the sales channel.
- </p>
- )}
- </div>
- <div className="flex gap-2 items-center">
- <Badge>ID: {channel.id}</Badge>
- <Badge variant={channel.active ? "successful" : "destructive"}>
- {channel.active ? "Active" : "Inactive"}
- </Badge>
- <div className="flex flex-row gap-2">
- <Button
- variant="outline"
- disabled={false}
- className="ml-4"
- onClick={() =>
- navigate(`/settings/sales-channels/${channel.id}/edit`)
- }
- >
- Edit
- </Button>
- <DeleteSalesChannelButton
- channelId={channel.id}
- disabled={channel.salesChannelTypeId === 1}
- tooltip={
- channel.salesChannelTypeId === 1
- ? "In-store sales channels cannot be deleted"
- : undefined
- }
- onDelete={() => {
- queryClient.setQueryData(
- queryKey,
- (prev: ApiPageEntitySalesChannel) => {
- return {
- ...prev,
- content: prev.content?.filter(
- (c) => c.id !== channel.id,
- ),
- };
- },
- );
- }}
- />
- </div>
- </div>
- </li>
- );
- })}
- </ul>
- <StyledPaginationControls
- page={page}
- totalPages={salesChannels?.totalPages}
- totalCount={salesChannels?.totalElements}
- />
-
- {/* Create Sales Channel Wizard */}
- <CreateSalesChannelWizardV2
- isOpen={createDisclosure.isOpen}
- onClose={createDisclosure.onClose}
- onSave={(channel) => {
- // Invalidate the query to refetch fresh data with complete sales channel info
- void queryClient.invalidateQueries({ queryKey });
- }}
- />
- </SettingsBlock>
- );
-};
-
-const DeleteSalesChannelButton: React.FC<{
- channelId: number;
- onDelete: () => void;
- disabled: boolean;
- tooltip?: string;
-}> = ({ channelId, onDelete, disabled, tooltip }) => {
- const toast = useToast();
- const { mutateAsync: deleteSalesChannel, isPending: isLoading } =
- useDeleteSalesChannel({
- mutation: {
- onSuccess: (resp) => {
- toast({
- status: "success",
- title: "Sales channel deleted",
- description: "Your sales channel has been deleted",
- });
- },
- onError: (err: any) => {
- if (isAxios400(err)) {
- toast({
- title: "Error",
- status: "error",
- description: `Request failed. ${err}`,
- });
- } else {
- toast({
- title: "Error",
- status: "error",
- description: "An error occurred while deleting the sales channel",
- });
- captureException(err);
- }
- },
- },
- });
- return (
- <TooltipProvider>
- <Tooltip>
- <TooltipTrigger>
- <DeleteButtonWithWarning
- isLoading={isLoading}
- disabled={disabled}
- onDelete={async () => {
- await deleteSalesChannel({
- id: channelId,
- });
- onDelete();
- }}
- />
- </TooltipTrigger>
- <TooltipContent>
- <p>{tooltip}</p>
- </TooltipContent>
- </Tooltip>
- </TooltipProvider>
- );
-};
diff --git a/src/pages/Settings/Saleschannels/SalesChannelSettingsPanel.tsx b/src/pages/Settings/Saleschannels/SalesChannelSettingsPanel.tsx
new file mode 100644
index 00000000..f2ae895b
--- /dev/null
+++ b/src/pages/Settings/Saleschannels/SalesChannelSettingsPanel.tsx
@@ -0,0 +1,217 @@
+import { useDisclosure, useToast } from "@chakra-ui/react";
+import { captureException } from "@sentry/react";
+import { useQueryClient } from "@tanstack/react-query";
+import { StyledPaginationControls } from "components/common/StyledPaginationControls/StyledPaginationControls";
+import { DeleteButtonWithWarning } from "components/DeleteButtonWithWarning";
+import { SalesChannelBadge } from "components/SalesChannels/SalesChannelBadge";
+import { UpsertSalesChannelDialog } from "components/SalesChannels/UpsertSalesChannelDialog";
+import { SettingsBlock } from "components/SettingsComponents/SettingsBlock";
+import { Badge } from "components/ui/badge";
+import { Button } from "components/ui/button";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "components/ui/tooltip";
+import { useEntitySelected } from "context/EntityProvider";
+import { useDocumentTitle } from "hooks/useDocumentTitle";
+import { PlusIcon } from "lucide-react";
+import { useState } from "react";
+import {
+ ApiPageEntitySalesChannel,
+ EntitySalesChannel,
+ useDeleteSalesChannel,
+ useListSalesChannels,
+} from "src/spring-generated";
+import { NumberParam, useQueryParams, withDefault } from "use-query-params";
+import { isAxios400 } from "utils/errors";
+
+type SalesChannelSettingsPanelProps = {};
+
+export const SalesChannelSettingsPanel: React.FC<
+ SalesChannelSettingsPanelProps
+> = () => {
+ useDocumentTitle("Settings - Sales Channel");
+ const [entity] = useEntitySelected();
+ const queryClient = useQueryClient();
+ const [{ page }] = useQueryParams({
+ page: withDefault(NumberParam, 1),
+ });
+ const { data: salesChannels, queryKey } = useListSalesChannels({
+ entityIds: [entity.id],
+ page: page - 1,
+ size: 30,
+ });
+ const [editingChannel, setEditingChannel] = useState<EntitySalesChannel>();
+ const disclosure = useDisclosure({
+ onClose: () => {
+ setEditingChannel(undefined);
+ },
+ });
+
+ return (
+ <SettingsBlock
+ flexGrow={1}
+ header={
+ <div className="w-full flex flex-row justify-between">
+ <h1 className="text-2xl font-bold">Sales Channels</h1>
+ <Button onClick={disclosure.onOpen}>
+ <PlusIcon className="w-4 h-4 mr-2" />
+ New Sales Channel
+ </Button>
+ </div>
+ }
+ >
+ <ul className="space-y-4 w-full flex-grow flex flex-col">
+ {salesChannels?.content?.map((channel) => (
+ <li
+ key={channel.id}
+ className="flex items-center border-b justify-between p-2 rounded-md"
+ >
+ <div>
+ <div className="flex flex-row items-center gap-2">
+ <h3 className="font-semibold">{channel.name}</h3>
+ <SalesChannelBadge salesChannel={channel} />
+ </div>
+ {channel.accountId && (
+ <p className="text-sm text-gray-600">
+ Account ID: {channel.accountId}
+ </p>
+ )}
+ </div>
+ <div className="flex gap-2 items-center">
+ <Badge>ID: {channel.id}</Badge>
+ <Badge variant={channel.active ? "successful" : "destructive"}>
+ {channel.active ? "Active" : "Inactive"}
+ </Badge>
+ <div className="flex flex-row gap-2">
+ <Button
+ variant="outline"
+ disabled={channel.salesChannelTypeId === 1}
+ className="ml-4"
+ onClick={() => {
+ setEditingChannel(channel);
+ disclosure.onOpen();
+ }}
+ >
+ Edit
+ </Button>
+ <DeleteSalesChannelButton
+ channelId={channel.id}
+ disabled={channel.salesChannelTypeId === 1}
+ tooltip={
+ channel.salesChannelTypeId === 1
+ ? "In-store sales channels cannot be deleted"
+ : undefined
+ }
+ onDelete={() => {
+ queryClient.setQueryData(
+ queryKey,
+ (prev: ApiPageEntitySalesChannel) => {
+ return {
+ ...prev,
+ content: prev.content?.filter(
+ (c) => c.id !== channel.id,
+ ),
+ };
+ },
+ );
+ }}
+ />
+ </div>
+ </div>
+ </li>
+ ))}
+ </ul>
+ <StyledPaginationControls
+ page={page}
+ totalPages={salesChannels?.totalPages}
+ totalCount={salesChannels?.totalElements}
+ />
+ <UpsertSalesChannelDialog
+ key={editingChannel?.id}
+ isOpen={disclosure.isOpen}
+ onClose={disclosure.onClose}
+ channel={editingChannel}
+ onSave={(channel) => {
+ queryClient.setQueryData(
+ queryKey,
+ (prev: ApiPageEntitySalesChannel) => {
+ if (prev.content?.find((c) => c.id === channel.id)) {
+ return {
+ ...prev,
+ content: prev.content?.map((c) =>
+ c.id === channel.id ? channel : c,
+ ),
+ };
+ }
+ return {
+ ...prev,
+ content: [...(prev.content ?? []), channel],
+ };
+ },
+ );
+ }}
+ />
+ </SettingsBlock>
+ );
+};
+
+const DeleteSalesChannelButton: React.FC<{
+ channelId: number;
+ onDelete: () => void;
+ disabled: boolean;
+ tooltip?: string;
+}> = ({ channelId, onDelete, disabled, tooltip }) => {
+ const toast = useToast();
+ const { mutateAsync: deleteSalesChannel, isPending: isLoading } =
+ useDeleteSalesChannel({
+ mutation: {
+ onSuccess: (resp) => {
+ toast({
+ status: "success",
+ title: "Sales channel deleted",
+ description: "Your sales channel has been deleted",
+ });
+ },
+ onError: (err: any) => {
+ if (isAxios400(err)) {
+ toast({
+ title: "Error",
+ status: "error",
+ description: `Request failed. ${err}`,
+ });
+ } else {
+ toast({
+ title: "Error",
+ status: "error",
+ description: "An error occurred while deleting the sales channel",
+ });
+ captureException(err);
+ }
+ },
+ },
+ });
+ return (
+ <TooltipProvider>
+ <Tooltip>
+ <TooltipTrigger>
+ <DeleteButtonWithWarning
+ isLoading={isLoading}
+ disabled={disabled}
+ onDelete={async () => {
+ await deleteSalesChannel({
+ id: channelId,
+ });
+ onDelete();
+ }}
+ />
+ </TooltipTrigger>
+ <TooltipContent>
+ <p>{tooltip}</p>
+ </TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ );
+};
diff --git a/src/pages/Settings/SettingsPage.tsx b/src/pages/Settings/SettingsPage.tsx
index bea68f97..63243e0b 100644
--- a/src/pages/Settings/SettingsPage.tsx
+++ b/src/pages/Settings/SettingsPage.tsx
@@ -1,4 +1,3 @@
-import PGliteProvider from "components/pg-lite/PGliteProvider";
import { LoadingSpinner } from "components/ui/loading-spinner";
import {
useEntitySelected,
@@ -93,7 +92,7 @@ const RolesSettingsPanel = lazy(() =>
})),
);
const SalesChannelSettingsPanel = lazy(() =>
- import("./SalesChannels/SalesChannelSettingsPanel").then((m) => ({
+ import("./Saleschannels/SalesChannelSettingsPanel").then((m) => ({
default: m.SalesChannelSettingsPanel,
})),
);
@@ -373,9 +372,7 @@ const SettingsPage: React.FC<SettingsPageProps> = () => {
link: "devices",
component: (
<Suspense fallback={<SettingsLoadingFallback />}>
- <PGliteProvider>
- <DeviceManagementPanel key={entity?.id} />
- </PGliteProvider>
+ <DeviceManagementPanel key={entity?.id} />
</Suspense>
),
requires: "entity/*:manage",
diff --git a/src/pages/Settings/Tags/TagBadge.tsx b/src/pages/Settings/Tags/TagBadge.tsx
index 2413a94d..ec082517 100644
--- a/src/pages/Settings/Tags/TagBadge.tsx
+++ b/src/pages/Settings/Tags/TagBadge.tsx
@@ -89,7 +89,6 @@ export const TagBadge: React.FC<TagBadgeProps> = ({
e.stopPropagation();
void deleteTag({} as never);
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[deleteTag, onDelete, tag.id, containerRef],
);
diff --git a/src/pages/Settings/Vendors/VendorSettingsPanel.tsx b/src/pages/Settings/Vendors/VendorSettingsPanel.tsx
index 1bc63564..067f54fa 100644
--- a/src/pages/Settings/Vendors/VendorSettingsPanel.tsx
+++ b/src/pages/Settings/Vendors/VendorSettingsPanel.tsx
@@ -134,7 +134,6 @@ export const VendorSettingsPanel: React.FC = () => {
if (data?.content?.length) {
void preferredItemCount.refetch();
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [data?.content, page, preferredItemCount.refetch]);
const { data: entityVendorCountMap, refetch: refetchCount } =
diff --git a/src/pages/TransactionPage.tsx b/src/pages/TransactionPage.tsx
index 1f9e3d8b..865116d6 100644
--- a/src/pages/TransactionPage.tsx
+++ b/src/pages/TransactionPage.tsx
@@ -35,17 +35,14 @@ import {
} from "components/ui/tooltip";
import { useToast } from "components/ui/use-toast";
import { captureException } from "config/sentry/TransformitySentry";
-import { useUserAuth } from "context/AuthenticationContext/AuthenticationContext";
import { useRegisterProvider } from "context/RegisterProvider";
import { SalesPaymentProvider } from "context/Sales/SalesPaymentContext";
import { useDocumentTitle } from "hooks/useDocumentTitle";
import { useKeypress } from "hooks/useKeypress";
-import { useOrderItemDecisionUpdater } from "hooks/useOrderItemDecisionUpdater";
import { round } from "lodash-es";
import { Clock, LinkIcon, ScanLine, UserCheck2 } from "lucide-react";
import { useMemo, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
-import { FulfillmentConfirmationModal } from "src/components/fulfillment/FulfillmentConfirmationModal";
import Loading from "src/components/Loading";
import { CustomerConfirmAlert } from "src/components/loyalty/CustomerConfirmAlert";
import { CustomerLookupModal } from "src/components/loyalty/CustomerLookupModal/CustomerLookupModal";
@@ -65,10 +62,6 @@ import { useGetLoyaltyCustomer } from "src/generated/hooks/useGetLoyaltyCustomer
import { EntityConfigKey } from "src/generated/types/EntityConfigKey";
import { useEntityConfig } from "src/hooks/useEntityConfig";
import { cn } from "src/lib/utils";
-import {
- useGetFulfillment,
- useListOrderItemDecisions,
-} from "src/phoenix-generated";
import {
useGetEntitySalesChannelById,
useHasDeleteAccess,
@@ -96,7 +89,6 @@ const TransactionPage = () => {
const { txId } = useParams();
const navigate = useNavigate();
const [entity] = useEntitySelected();
- const { user } = useUserAuth();
const { register } = useRegisterProvider();
const finishTransactionModal = useDisclosure();
const flagEnabled = useEntityConfig(
@@ -118,8 +110,6 @@ const TransactionPage = () => {
const { id: loyaltyProgramId } = useLoyaltyProgramIdOptional();
const [showDeleteTransactionAlert, setShowDeleteTransactionAlert] =
useState(false);
- const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
- const [showFulfillmentModal, setShowFulfillmentModal] = useState(false);
const transactionRes = useGetTransactionById(+(txId ?? new Error("")), {
query: {
enabled: true,
@@ -163,45 +153,6 @@ const TransactionPage = () => {
},
},
);
- const { data: orderItemDecisions, refetch: orderItemDecisionsRefetch } =
- useListOrderItemDecisions(
- {
- transaction_id: transactionDetail?.id ?? 0,
- offset: 0,
- limit: 100,
- },
- {
- query: {
- enabled: !!transactionDetail?.id,
- },
- },
- );
- const orderCanBeFulfilled = useMemo(() => {
- return (
- (orderItemDecisions?.length ?? 0) > 0 &&
- orderItemDecisions?.every((decision) => decision.status !== "CREATED")
- );
- }, [orderItemDecisions]);
- console.log(orderItemDecisions);
- const fulfillmentId = useMemo(() => {
- const set = new Set(
- orderItemDecisions?.map((decision) => decision.fulfillmentId),
- );
- if (set.size > 1) {
- captureException(
- new Error("Multiple fulfillment ids found for transaction"),
- );
- }
- return set.values().next().value;
- }, [orderItemDecisions]);
- const { data: fulfillment, refetch: fulfillmentRefetch } = useGetFulfillment(
- fulfillmentId ?? "",
- {
- query: {
- enabled: !!fulfillmentId,
- },
- },
- );
const { mutateAsync: linkCustomer } = useLinkCustomerToTransaction(
transactionDetail?.id ?? 0,
{
@@ -234,57 +185,6 @@ const TransactionPage = () => {
const { data: hasDeleteAccess } = useHasDeleteAccess();
- const { updateDecisions, isUpdating: isProcessingBulkAction } =
- useOrderItemDecisionUpdater({
- onSuccess: () => {
- // Refetch order item decisions after status update
- void orderItemDecisionsRefetch();
- // Clear selection after successful bulk action
- setSelectedRows(new Set());
- },
- });
-
- // Row selection handlers
- const handleRowSelect = (itemId: number, isSelected: boolean) => {
- setSelectedRows((prev) => {
- const newSet = new Set(prev);
- if (isSelected) {
- newSet.add(itemId);
- } else {
- newSet.delete(itemId);
- }
- return newSet;
- });
- };
-
- const handleSelectAll = (isSelected: boolean) => {
- if (isSelected) {
- const allItemIds = new Set(
- transactionDetail?.transactionItems.map((item) => item.id) || [],
- );
- setSelectedRows(allItemIds);
- } else {
- setSelectedRows(new Set());
- }
- };
-
- // Bulk action handlers
- const handleBulkAction = async (status: "ACCEPTED" | "REJECTED") => {
- if (selectedRows.size === 0 || !orderItemDecisions || !user?.uid) return;
-
- const decisionsToUpdate = orderItemDecisions
- .filter((decision) => selectedRows.has(decision.transactionItemId))
- .map((decision) => ({
- decisionId: decision.id,
- status,
- userId: user.uid,
- source: `${entity.id.toString()} register:${register.registerNumber?.toString() ?? "unknown"}`,
- reason: `Bulk ${status.toLowerCase()} via cashier interface`,
- }));
-
- await updateDecisions(decisionsToUpdate);
- };
-
useKeypress(
new Map([
[
@@ -370,58 +270,9 @@ const TransactionPage = () => {
</div>
<div className="p-4 w-full h-full grid grid-cols-[3fr_1fr] gap-2 overflow-hidden">
<div className="grid grid-rows-[4fr_auto] gap-2 overflow-hidden">
- <Card
- title="Items Summary"
- headerActions={
- <>
- {fulfillment && orderCanBeFulfilled && (
- <div className="flex items-center gap-2">
- <Button
- size="sm"
- disabled={!register.registerNumber}
- onClick={() => setShowFulfillmentModal(true)}
- >
- {fulfillment.status === "COMPLETED"
- ? "View Fulfillment"
- : register.registerNumber
- ? "Complete Order"
- : "Select Register to Complete Order"}
- </Button>
- </div>
- )}
- {(orderItemDecisions?.length ?? 0) > 0 &&
- selectedRows.size > 0 ? (
- <div className="flex gap-2">
- <PermissionedButton
- requires="orderitemdecision/*:update-status"
- size="sm"
- variant="outline"
- disabled={isProcessingBulkAction}
- onClick={() => handleBulkAction("ACCEPTED")}
- >
- Accept Selected ({selectedRows.size})
- </PermissionedButton>
- <PermissionedButton
- requires="orderitemdecision/*:update-status"
- size="sm"
- variant="destructive"
- disabled={isProcessingBulkAction}
- onClick={() => handleBulkAction("REJECTED")}
- >
- Reject Selected ({selectedRows.size})
- </PermissionedButton>
- </div>
- ) : undefined}
- </>
- }
- >
+ <Card title="Items Summary">
<TransactionItemsTable
items={transactionDetail.transactionItems}
- orderItemDecisions={orderItemDecisions}
- selectedRows={selectedRows}
- onRowSelect={handleRowSelect}
- onSelectAll={handleSelectAll}
- onDecisionUpdated={() => orderItemDecisionsRefetch()}
/>
</Card>
<Card title="Transaction Summary">
@@ -628,13 +479,6 @@ const TransactionPage = () => {
resetCartToCurrentItems={() => undefined}
salesChannel={salesChannel}
payAfterConfirm={payAfterConfirm}
- // Payment method functions (fallback implementations for transaction completion context)
- paymentMethodTypeToPaymentMethod={{}}
- calculateMethodsWithPrices={() => []}
- findBestPaymentMethod={() => null}
- isCalculatingBackgroundPaymentMethodTotals={false}
- selectedSalesChannel={undefined}
- setSkipSetItemsInCart={() => undefined}
>
<FinishTransacationPaymentModal
isOpen={finishTransactionModal.isOpen}
@@ -642,18 +486,6 @@ const TransactionPage = () => {
/>
</SalesPaymentProvider>
)}
- {fulfillmentId && (
- <FulfillmentConfirmationModal
- isOpen={showFulfillmentModal}
- onClose={() => setShowFulfillmentModal(false)}
- fulfillmentId={fulfillmentId}
- onSuccess={() => {
- void transactionRes.refetch();
- void orderItemDecisionsRefetch();
- void fulfillmentRefetch();
- }}
- />
- )}
</>
);
};
@@ -662,10 +494,9 @@ interface CardProps {
title: string;
children: React.ReactNode;
className?: string;
- headerActions?: React.ReactNode;
}
-const Card = ({ title, children, className, headerActions }: CardProps) => {
+const Card = ({ title, children, className }: CardProps) => {
return (
<div
className={cn(
@@ -673,9 +504,8 @@ const Card = ({ title, children, className, headerActions }: CardProps) => {
className,
)}
>
- <div className="bg-weak-100 border-b border-theme-gray-3 p-4 flex items-center justify-between">
+ <div className="bg-weak-100 border-b border-theme-gray-3 p-4">
<p className="font-bold text-xl">{title}</p>
- {headerActions}
</div>
<div className="px-4 py-4 overflow-y-auto h-full">{children}</div>
</div>
diff --git a/src/pages/TransactionsPage.tsx b/src/pages/TransactionsPage.tsx
index 7d156607..95a97ea3 100644
--- a/src/pages/TransactionsPage.tsx
+++ b/src/pages/TransactionsPage.tsx
@@ -58,10 +58,6 @@ const ShowTransactions = {
SUCCEEDED: [TransactionStatus.SUCCESS],
REFUND: [TransactionStatus.REFUND],
PENDING: [TransactionStatus.PENDING, TransactionStatus.CREATED],
- // Status for transactions where order item decisions are pending
- DECISION_REQUIRED: [TransactionStatus.SUCCESS],
- // Status where fulfillment is pending
- FULFILLMENT_REQUIRED: [TransactionStatus.SUCCESS],
ALL: undefined,
};
@@ -118,32 +114,17 @@ const TransactionsPage = (_: TransactionsPageProps) => {
entityId: entity.id,
page: page - 1,
size: 20,
- registerNumber:
- selectedRegister &&
- showTransactions !== "DECISION_REQUIRED" &&
- showTransactions !== "FULFILLMENT_REQUIRED"
- ? selectedRegister
- : undefined,
+ registerNumber: selectedRegister ?? undefined,
paymentForm: !!selectedPayForm ? [selectedPayForm] : undefined,
salesChannelIds:
selectedSalesChannels.length > 0 ? selectedSalesChannels : undefined,
...(enabledClosings && { closed: false }),
sort: ["completedAt,desc", "createdDate,desc"],
transactionStatus: ShowTransactions[showTransactions],
- hasPendingDecisions:
- showTransactions === "DECISION_REQUIRED"
- ? true
- : showTransactions === "FULFILLMENT_REQUIRED"
- ? false
- : undefined,
- hasPendingFulfillment:
- showTransactions === "FULFILLMENT_REQUIRED" ? true : undefined,
- ...(!enabledClosings &&
- showTransactions !== "DECISION_REQUIRED" &&
- showTransactions !== "FULFILLMENT_REQUIRED" && {
- startDate,
- endDate,
- }),
+ ...(!enabledClosings && {
+ startDate,
+ endDate,
+ }),
},
{
query: {
@@ -258,7 +239,7 @@ const TransactionsPage = (_: TransactionsPageProps) => {
>
{Object.entries(ShowTransactions).map(([key]) => (
<RadioCard key={key} value={key}>
- {key.replace("_", " ")}
+ {key}
</RadioCard>
))}
</RadioCardGroup>
diff --git a/src/pages/gift_card/GiftCardReport.tsx b/src/pages/gift_card/GiftCardReport.tsx
index 62a5f90f..8a8ad7af 100644
--- a/src/pages/gift_card/GiftCardReport.tsx
+++ b/src/pages/gift_card/GiftCardReport.tsx
@@ -170,7 +170,6 @@ const GiftCardReport = () => {
isLoading.setFalse();
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
setStatus,
giftCardApi,
diff --git a/src/pages/inventory_transfer/InventoryTransfersPage.tsx b/src/pages/inventory_transfer/InventoryTransfersPage.tsx
index a4da390f..7f823191 100644
--- a/src/pages/inventory_transfer/InventoryTransfersPage.tsx
+++ b/src/pages/inventory_transfer/InventoryTransfersPage.tsx
@@ -115,7 +115,6 @@ export const useListInventoryTransfersHook = () => {
number: data.page.number + 1,
});
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [data]);
return {
@@ -364,7 +363,6 @@ const InventoryTransfersPage = () => {
},
}),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
allPossibleEntities,
entityId,
diff --git a/src/pages/inventory_transfer/PrintInventoryTransferPage.tsx b/src/pages/inventory_transfer/PrintInventoryTransferPage.tsx
index e5449b1d..0b612574 100644
--- a/src/pages/inventory_transfer/PrintInventoryTransferPage.tsx
+++ b/src/pages/inventory_transfer/PrintInventoryTransferPage.tsx
@@ -96,7 +96,11 @@ const PrintInventoryTransferPage: React.FC<PrintInvoicePageProps> = ({}) => {
role="button"
tabIndex={0}
onClick={() => {
- if (hasPermission(`item/*:read`)) {
+ if (
+ hasPermission(
+ `item/*:read`,
+ )
+ ) {
setSelectedItem(row.original.entityItemSent);
}
}}
@@ -161,7 +165,6 @@ const PrintInventoryTransferPage: React.FC<PrintInvoicePageProps> = ({}) => {
footer: SumFooterCell,
}),
];
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [inventoryTransfer]);
if (!id) {
@@ -186,7 +189,6 @@ const PrintInventoryTransferPage: React.FC<PrintInvoicePageProps> = ({}) => {
</SkeletonText>
<SkeletonText isLoaded={!!inventoryTransfer}>
<HStack w="100%">
- ur
<Heading size="md">
{
allPossibleEntities.find(
diff --git a/src/pages/inventory_transfer/edit/InventoryTransferEditTable.tsx b/src/pages/inventory_transfer/edit/InventoryTransferEditTable.tsx
index 055791ef..4a8fe0bb 100644
--- a/src/pages/inventory_transfer/edit/InventoryTransferEditTable.tsx
+++ b/src/pages/inventory_transfer/edit/InventoryTransferEditTable.tsx
@@ -441,7 +441,6 @@ const InventoryTablePageTableInner = (
setAddingItem(true);
}
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
inventoryTransfer.id,
postInventoryTransferItem,
@@ -783,7 +782,6 @@ const InventoryTablePageTableInner = (
},
},
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[
canEditCellRef,
hideColumns,
diff --git a/src/pages/invoices/InvoicePage/InvoiceCommonHeader.tsx b/src/pages/invoices/InvoicePage/InvoiceCommonHeader.tsx
index 05162421..cad7942d 100644
--- a/src/pages/invoices/InvoicePage/InvoiceCommonHeader.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceCommonHeader.tsx
@@ -18,12 +18,14 @@ import { GridApi } from "ag-grid-community";
import { type SelectInstance } from "chakra-react-select";
import { SavingIndicator } from "components/common/SavingIndicator/SavingIndicator";
import { InvoiceStatusTag } from "components/invoices/InvoiceStatusTag";
+import { captureException } from "config/sentry/TransformitySentry";
import { useInvoiceContext } from "context/InvoiceContext";
import { format } from "date-fns";
import { useAllVendors } from "hooks/useAllVendors";
-import { ExternalLink, SearchIcon, UnfoldHorizontal, X } from "lucide-react";
+import { ExternalLink, FileText, SearchIcon, X } from "lucide-react";
import React, { useMemo, useRef } from "react";
import { Link } from "react-router-dom";
+import { useGetDownloadAssetLink } from "src/spring-generated/hooks";
import { CreateItemModalRefProps } from "./InvoicePage";
import InvoiceSearchAddItemSelect from "./InvoiceSearchAddItemSelect";
import { InvoiceTotal } from "./InvoiceTotal";
@@ -37,7 +39,6 @@ interface InvoiceCommonHeaderProps {
setActiveStep: (step: number) => void;
invoiceTableGridApiRef: React.RefObject<GridApi | undefined>;
onAddItem?: (item: EntityItemDetail | undefined) => void;
- onComparePdf?: () => void;
createItemModalRef: React.RefObject<CreateItemModalRefProps | null>;
asyncSelectInputRef: React.RefObject<SelectInstance<any | null>>;
}
@@ -49,12 +50,12 @@ export const InvoiceCommonHeader: React.FC<InvoiceCommonHeaderProps> = ({
setActiveStep,
invoiceTableGridApiRef,
onAddItem = () => {},
- onComparePdf = () => {},
createItemModalRef,
asyncSelectInputRef,
}) => {
const inputRef = useRef<HTMLInputElement | null>(null);
const { sums, isLoading, savingItemIds, isEditing } = useInvoiceContext();
+ const downloadAssetLinkMutation = useGetDownloadAssetLink();
const onChange = (value: string) => {
invoiceTableGridApiRef.current?.setGridOption("quickFilterText", value);
@@ -64,16 +65,35 @@ export const InvoiceCommonHeader: React.FC<InvoiceCommonHeaderProps> = ({
return ((sums?.totalCost ?? 0) + (invoice?.other ?? 0)).toFixed(2);
}, [sums?.totalCost, invoice.other]);
+ const handleDownloadPDF = async () => {
+ if (!invoice.cohortAssetId) return;
+
+ try {
+ const downloadUrl = await downloadAssetLinkMutation.mutateAsync({
+ data: {
+ cohortAssetId: invoice.cohortAssetId,
+ entityId: invoice.entityId,
+ },
+ });
+
+ // Open the PDF in a new tab
+ window.open(downloadUrl, "_blank");
+ } catch (error) {
+ console.error("Error downloading PDF:", error);
+ captureException(error);
+ }
+ };
+
return (
- <div className="flex flex-col gap-y-4 w-full">
+ <div className="flex flex-col gap-y-4 w-[95vw]">
<HStack
alignItems="start"
spacing={0}
- w="100%"
+ w={"95vw"}
justifyContent={"space-between"}
gap={2}
>
- <Flex gap={3} alignItems={"center"} wrap={"wrap"}>
+ <Flex gap={3} flexShrink={0} alignItems={"center"}>
<HStack
textColor="gray.600"
padding={"0.5rem 0.75rem"}
@@ -101,6 +121,18 @@ export const InvoiceCommonHeader: React.FC<InvoiceCommonHeaderProps> = ({
<InvoiceStatusTag status={invoice.status} />
</HStack>
<UpdateInvoiceDialog invoice={invoice} />
+ {invoice.cohortAssetId && (
+ <Button
+ variant="outline"
+ className="px-2"
+ aria-label="Download PDF"
+ onClick={handleDownloadPDF}
+ isLoading={downloadAssetLinkMutation.isPending}
+ >
+ <FileText className="size-5 text-theme-gray-1" />
+ <ExternalLink className="size-4 text-theme-gray-1" />
+ </Button>
+ )}
{activeStep === 0 && (
<Popover placement="bottom-start" initialFocusRef={inputRef}>
<PopoverTrigger>
@@ -155,12 +187,6 @@ export const InvoiceCommonHeader: React.FC<InvoiceCommonHeaderProps> = ({
saving={savingItemIds.size > 0 || isLoading}
savingCount={savingItemIds.size}
/>
- {activeStep === 0 && invoice.cohortAssetId && (
- <Button variant="outline" className="px-2" onClick={onComparePdf}>
- <UnfoldHorizontal className="size-5 mr-1 text-blue-500" />{" "}
- <span className="text-blue-500">Compare PDF</span>
- </Button>
- )}
</Flex>
<Flex gap={"1.5rem"}>
<div className="flex items-center gap-x-2">
diff --git a/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPage.tsx b/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPage.tsx
index d1ccb116..6283bc55 100644
--- a/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPage.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPage.tsx
@@ -102,7 +102,7 @@ export const InvoiceEditPage: React.FC<InvoiceEditPageProps> = forwardRef(
return (
<>
- <Card w="100%" minH={0} flexGrow={1} border={"none"} shadow={"none"}>
+ <Card w="95vw" minH={0} flexGrow={1} border={"none"} shadow={"none"}>
<InvoicePageTable
isEditing={isEditing}
setLinkingItem={setLinkingItem}
@@ -116,7 +116,6 @@ export const InvoiceEditPage: React.FC<InvoiceEditPageProps> = forwardRef(
invoiceTableGridApiRef={invoiceTableGridApiRef}
/>
</Card>
-
<SwapItemModal
{...linkItemDisclosure}
linkingInvoiceItem={`${linkingItem?.invoiceItemDescription || ""} ${linkingItem?.sku ? "(" + linkingItem.sku + ")" : ""}`}
diff --git a/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPageTable.tsx b/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPageTable.tsx
index c6681976..3e34365a 100644
--- a/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPageTable.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceEditStep/InvoiceEditPageTable.tsx
@@ -541,7 +541,6 @@ const InvoicePageTableInner = (
}
},
}),
- // eslint-disable-next-line react-hooks/exhaustive-deps
[asyncSelectInputRef, invoice.cohortVendorId, queryClient, setAddingItem],
);
@@ -703,7 +702,6 @@ const InvoicePageTableInner = (
searchControlActiveStyles();
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
invoice.id,
linkItemDisclosure,
@@ -933,7 +931,6 @@ const InvoicePageTableInner = (
hide: true,
},
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
@@ -1130,7 +1127,6 @@ const InvoicePageTableInner = (
api.removeEventListener("rowDataUpdated", applyFocusToRenderedRows);
};
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [focusedCell]);
const removeHoverClasses = () => {
diff --git a/src/pages/invoices/InvoicePage/InvoiceFooter.tsx b/src/pages/invoices/InvoicePage/InvoiceFooter.tsx
index f157c7c7..f67fe132 100644
--- a/src/pages/invoices/InvoicePage/InvoiceFooter.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceFooter.tsx
@@ -72,7 +72,7 @@ export const InvoiceFooter: React.FC<InvoiceFooterProps> = ({
return (
<Grid
- w="100%"
+ w={"95vw"}
justifyContent={"space-between"}
gridTemplateColumns={"1fr 1fr"}
>
diff --git a/src/pages/invoices/InvoicePage/InvoicePage.tsx b/src/pages/invoices/InvoicePage/InvoicePage.tsx
index 04d39339..223e3bcd 100644
--- a/src/pages/invoices/InvoicePage/InvoicePage.tsx
+++ b/src/pages/invoices/InvoicePage/InvoicePage.tsx
@@ -10,23 +10,17 @@ import {
import { Stack, UseDisclosureProps, useSteps } from "@chakra-ui/react";
import { GridApi } from "ag-grid-community";
import { SelectInstance } from "chakra-react-select";
-import { captureException } from "config/sentry/TransformitySentry";
import { InvoiceProvider } from "context/InvoiceContext";
import { useDocumentTitle } from "hooks/useDocumentTitle";
import { useEffect, useMemo, useRef, useState } from "react";
-import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
-import {
- ItemSearchResponseDto,
- useGetDownloadAssetLink,
-} from "src/spring-generated";
+import { ItemSearchResponseDto } from "src/spring-generated";
import Loading from "../../../components/Loading";
import { NavBarPlain } from "../../../components/navbar/NavBarPlain";
import { useAllVendors } from "../../../hooks/useAllVendors";
import { InvoiceCommonHeader } from "./InvoiceCommonHeader";
import { InvoiceFooter } from "./InvoiceFooter";
import { invoicePageSteps } from "./InvoicePageStepper";
-import { InvoicePdfDrawer } from "./InvoicePdfDrawer";
export interface AddItemRefProps {
addItem?: (
@@ -59,9 +53,6 @@ const InvoicePage = () => {
const { invoice, setInvoice, refetch } = useInvoice({ id });
const [searchParams, setSearchParams] = useSearchParams();
const { toast } = useToast();
- const downloadAssetLinkMutation = useGetDownloadAssetLink();
- const [pdfUrl, setPdfUrl] = useState<string>("");
- const [openPdfViewer, setOpenPdfViewer] = useState(false);
// Call useListInvoices at component level with enabled option
const { data: searchInvoice } = useListInvoices(
@@ -98,7 +89,6 @@ const InvoicePage = () => {
title: "Duplicate invoices found",
description: `There are multiple invoices with the same invoice id. Other invoice IDs: ${otherInvoiceIds}`,
variant: "destructive",
- duration: Infinity,
});
}
}, [searchInvoices, invoice?.id, toast]);
@@ -125,30 +115,6 @@ const InvoicePage = () => {
}
};
- const handleComparePdf = () => {
- if (!invoice) return;
- if (!invoice.cohortAssetId) return;
-
- setOpenPdfViewer(true);
- void downloadAssetLinkMutation
- .mutateAsync({
- data: {
- cohortAssetId: invoice.cohortAssetId,
- entityId: invoice.entityId,
- },
- })
- .then((scannedPdfUrl) => {
- setPdfUrl(scannedPdfUrl);
- })
- .catch((err) => {
- captureException(err);
- });
- };
-
- const handleClosePdfViewer = () => {
- setOpenPdfViewer(false);
- };
-
useEffect(() => {
if (searchParams.has("step")) {
const step = Number(searchParams.get("step"));
@@ -178,72 +144,43 @@ const InvoicePage = () => {
paddingBottom={10}
>
<NavBarPlain flexClassNames="!bg-[#F8F9FC] border-b border-b-theme-gray-3" />
- <div className="w-full px-6 flex-1 max-h-full flex flex-col">
- <PanelGroup direction="horizontal" className="flex h-full flex-1">
- <Panel
- defaultSize={75}
- minSize={50}
- className="flex flex-col gap-3 pr-4"
- >
- <InvoiceCommonHeader
- vendors={vendors}
- invoice={invoice}
- activeStep={activeStep}
- setActiveStep={setActiveStep}
- invoiceTableGridApiRef={invoiceTableGridApiRef}
- onAddItem={addItemToGrid as any}
- createItemModalRef={createItemModalRef}
- asyncSelectInputRef={asyncSelectInputRef}
- onComparePdf={handleComparePdf}
- />
- {/* @ts-expect-error */}
- {invoicePageSteps[activeStep].content({
- setActiveStep,
- vendors: vendors ?? new Map(),
- addItemRef: addItemRef,
- createItemModalRef: createItemModalRef,
- asyncSelectInputRef: asyncSelectInputRef,
- invoiceTableGridApiRef: invoiceTableGridApiRef,
- })}
- <InvoiceFooter
- activeStep={activeStep}
- onStepChange={(step, ctx) => {
- if (
- step === 1 &&
- ctx.invoice.status !== InvoiceStatus.COMPLETE
- ) {
- void ctx.saveInvoice({
- ...ctx.invoice,
- status: InvoiceStatus.ITEM_MANAGEMENT,
- });
- }
- if (step === -1) {
- navigate(-1);
- } else {
- setActiveStep(step);
- searchParams.set("step", step.toString());
- setSearchParams(searchParams);
- }
- }}
- />
- </Panel>
-
- {openPdfViewer && (
- <>
- <PanelResizeHandle className="w-2 bg-gray-200 hover:bg-blue-300 transition-colors cursor-col-resize flex items-center justify-center">
- <div className="w-0.5 h-8 bg-gray-400 rounded-full"></div>
- </PanelResizeHandle>
- <InvoicePdfDrawer
- open={openPdfViewer}
- pdfUrl={pdfUrl}
- invoiceNumber={invoice.invoiceId}
- invoiceId={invoice.id}
- onClose={handleClosePdfViewer}
- />
- </>
- )}
- </PanelGroup>
- </div>
+ <InvoiceCommonHeader
+ vendors={vendors}
+ invoice={invoice}
+ activeStep={activeStep}
+ setActiveStep={setActiveStep}
+ invoiceTableGridApiRef={invoiceTableGridApiRef}
+ onAddItem={addItemToGrid as any}
+ createItemModalRef={createItemModalRef}
+ asyncSelectInputRef={asyncSelectInputRef}
+ />
+ {/* @ts-expect-error */}
+ {invoicePageSteps[activeStep].content({
+ setActiveStep,
+ vendors: vendors ?? new Map(),
+ addItemRef: addItemRef,
+ createItemModalRef: createItemModalRef,
+ asyncSelectInputRef: asyncSelectInputRef,
+ invoiceTableGridApiRef: invoiceTableGridApiRef,
+ })}
+ <InvoiceFooter
+ activeStep={activeStep}
+ onStepChange={(step, ctx) => {
+ if (step === 1 && ctx.invoice.status !== InvoiceStatus.COMPLETE) {
+ void ctx.saveInvoice({
+ ...ctx.invoice,
+ status: InvoiceStatus.ITEM_MANAGEMENT,
+ });
+ }
+ if (step === -1) {
+ navigate(-1);
+ } else {
+ setActiveStep(step);
+ searchParams.set("step", step.toString());
+ setSearchParams(searchParams);
+ }
+ }}
+ />
</Stack>
</InvoiceProvider>
);
diff --git a/src/pages/invoices/InvoicePage/InvoicePdfDrawer.tsx b/src/pages/invoices/InvoicePage/InvoicePdfDrawer.tsx
deleted file mode 100644
index 27abf06e..00000000
--- a/src/pages/invoices/InvoicePage/InvoicePdfDrawer.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { X } from "lucide-react";
-import React, { memo, useState } from "react";
-import { Panel } from "react-resizable-panels";
-
-interface InvoicePdfDrawerProps {
- pdfUrl: string;
- invoiceNumber?: string;
- invoiceId?: number;
- open: boolean;
- onClose: () => void;
-}
-
-export const InvoicePdfDrawer: React.FC<InvoicePdfDrawerProps> = memo(
- ({ pdfUrl, invoiceNumber, invoiceId, open, onClose }) => {
- const [isLoading, setIsLoading] = useState(true);
-
- const handleIframeLoad = () => {
- setIsLoading(false);
- };
-
- const handleIframeError = () => {
- setIsLoading(false);
- };
-
- if (!open) return null;
-
- return (
- <Panel
- defaultSize={25}
- minSize={15}
- maxSize={50}
- className="flex flex-col rounded-md overflow-hidden bg-white border-l border-gray-200"
- >
- {/* Header */}
- {/* Header */}
- <div className="flex flex-row items-center justify-between p-4 border-b bg-gray-50">
- <div className="flex items-center space-x-2">
- <h3 className="text-lg font-semibold text-gray-900">PDF Viewer</h3>
- </div>
- <div>
- <X
- className="w-6 h-6 text-theme-gray-1 cursor-pointer hover:text-gray-700 transition-colors"
- onClick={onClose}
- />
- </div>
- </div>
-
- {/* Content */}
- <div className="flex-1 relative bg-gray-100 rounded-md">
- {isLoading && (
- <div className="absolute inset-0 flex items-center justify-center bg-white z-10">
- <div className="flex flex-col items-center space-y-2">
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
- <p className="text-sm text-gray-600">Loading Invoice...</p>
- </div>
- </div>
- )}
- <iframe
- src={pdfUrl}
- className="w-full h-full border-0"
- title={`Invoice Preview ${invoiceNumber || ""}`}
- onLoad={handleIframeLoad}
- onError={handleIframeError}
- />
- </div>
- </Panel>
- );
- },
-);
diff --git a/src/pages/invoices/InvoicePage/InvoicePricingStep/InvoicePricingPage.tsx b/src/pages/invoices/InvoicePage/InvoicePricingStep/InvoicePricingPage.tsx
index 8354126f..3706d162 100644
--- a/src/pages/invoices/InvoicePage/InvoicePricingStep/InvoicePricingPage.tsx
+++ b/src/pages/invoices/InvoicePage/InvoicePricingStep/InvoicePricingPage.tsx
@@ -139,7 +139,7 @@ export const InvoicePricingPage: React.FC<InvoicePricingPageProps> = () => {
if (!sums) return null;
return (
- <Card w="100%" border={"none"} shadow={"none"} flex={1} overflow="hidden">
+ <Card w="95vw" border={"none"} shadow={"none"} flex={1} overflow="hidden">
<CardHeader px={0}>
<HStack overflow="auto" justifyContent={"space-between"}>
<Stack
diff --git a/src/pages/invoices/InvoicePage/InvoiceSearchAddItemSelect.tsx b/src/pages/invoices/InvoicePage/InvoiceSearchAddItemSelect.tsx
index 89efaf61..f3230c97 100644
--- a/src/pages/invoices/InvoicePage/InvoiceSearchAddItemSelect.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceSearchAddItemSelect.tsx
@@ -390,7 +390,6 @@ export const InvoiceSearchAddItemSelect = (
ref.current?.onInputBlur(props);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [autoSelectSingleResult, searchResults]);
// const debouncedChangeHandler = useMemo(
diff --git a/src/pages/invoices/InvoicePage/InvoiceTotal.tsx b/src/pages/invoices/InvoicePage/InvoiceTotal.tsx
index a3260ebc..15367dc1 100644
--- a/src/pages/invoices/InvoicePage/InvoiceTotal.tsx
+++ b/src/pages/invoices/InvoicePage/InvoiceTotal.tsx
@@ -43,8 +43,6 @@ export const InvoiceTotal: React.FC<InvoiceTotalProps> = ({ invoice }) => {
<Tooltip
label="Invoice Total does not match sum of item subtotals + other."
isDisabled={totalDiff === 0}
- placement="bottom-end"
- offset={[0, 10]}
>
<VStack gap={"0.25rem"} alignItems={"flex-start"}>
<HStack>
diff --git a/src/pages/invoices/InvoicePage/SuspiciousPriceReviewModal.tsx b/src/pages/invoices/InvoicePage/SuspiciousPriceReviewModal.tsx
index a3b49e58..9cbd5c2d 100644
--- a/src/pages/invoices/InvoicePage/SuspiciousPriceReviewModal.tsx
+++ b/src/pages/invoices/InvoicePage/SuspiciousPriceReviewModal.tsx
@@ -81,8 +81,8 @@ export const SuspiciousPriceReviewModal: React.FC<
<div className="space-y-4">
<p className="text-orange-600 text-sm">
The following items have suspicious net unit costs that vary greatly
- from their previous cost. Please review the net unit costs and
- confirm they are correct.
+ from their previous cost. Please review the net unit costs and confirm
+ they are correct.
</p>
<Table>
diff --git a/src/pages/invoices/InvoicesPage/UploadInvoiceModal.tsx b/src/pages/invoices/InvoicesPage/UploadInvoiceModal.tsx
index 902e9c5d..48e4f421 100644
--- a/src/pages/invoices/InvoicesPage/UploadInvoiceModal.tsx
+++ b/src/pages/invoices/InvoicesPage/UploadInvoiceModal.tsx
@@ -118,7 +118,6 @@ export const UploadInvoiceModal = ({
} finally {
setIsUploading(false);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
createInvoice,
disclosure,
diff --git a/src/pages/item/ItemListDetailPage.tsx b/src/pages/item/ItemListDetailPage.tsx
index 2683afa9..be94c93f 100644
--- a/src/pages/item/ItemListDetailPage.tsx
+++ b/src/pages/item/ItemListDetailPage.tsx
@@ -484,7 +484,6 @@ const ItemListDetailPage = () => {
},
}),
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
[handleSaveItem, isUpdatePending, getOriginalItem, isDeletePending],
);
diff --git a/src/pages/item/ItemListsPage.tsx b/src/pages/item/ItemListsPage.tsx
index fee423d0..3f85cac5 100644
--- a/src/pages/item/ItemListsPage.tsx
+++ b/src/pages/item/ItemListsPage.tsx
@@ -140,7 +140,6 @@ const ItemListsPage = () => {
number: itemListsResults.page.number + 1,
}));
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSuccess, itemListsResults?.page.number, setPageState]);
const setName = useCallback(
diff --git a/src/pages/item/ItemSearchPage.tsx b/src/pages/item/ItemSearchPage.tsx
index 7691724b..960cb143 100644
--- a/src/pages/item/ItemSearchPage.tsx
+++ b/src/pages/item/ItemSearchPage.tsx
@@ -731,7 +731,6 @@ const ItemSearchPage = () => {
setValue("tags", tags.flat());
});
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryClient, reset, setValue]);
const handleTextInput = useCallback(
diff --git a/src/pages/item/ItemStateMinReport.tsx b/src/pages/item/ItemStateMinReport.tsx
index 78128ff2..32c19ae7 100644
--- a/src/pages/item/ItemStateMinReport.tsx
+++ b/src/pages/item/ItemStateMinReport.tsx
@@ -78,7 +78,6 @@ const ItemStateMinReport = () => {
(nextStateMin && item.price < nextStateMin)
);
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [stateMinViolations, currMonth, currYear, nextMonth]);
const { mutateAsync: patchItem } = usePatchItem();
@@ -214,7 +213,6 @@ const ItemStateMinReport = () => {
},
),
];
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [
stateMinViolations,
columnHelper,
diff --git a/src/pages/loyalty/CustomerLoyaltyProfile.tsx b/src/pages/loyalty/CustomerLoyaltyProfile.tsx
index f56e013d..f80aa4d3 100644
--- a/src/pages/loyalty/CustomerLoyaltyProfile.tsx
+++ b/src/pages/loyalty/CustomerLoyaltyProfile.tsx
@@ -79,7 +79,6 @@ const CustomerLoyaltyProfile: React.FC<CustomerLoyaltyProfileProps> = ({}) => {
queryClient.invalidateQueries({
queryKey: transactionsTableQueryKey.current,
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [pointsTableQueryKey, transactionsTableQueryKey, queryClient]);
const { data: houseAccountTotal } =
diff --git a/src/pages/marketing/components/CampaignHeader.tsx b/src/pages/marketing/components/CampaignHeader.tsx
index c9866b59..09495bee 100644
--- a/src/pages/marketing/components/CampaignHeader.tsx
+++ b/src/pages/marketing/components/CampaignHeader.tsx
@@ -64,7 +64,6 @@ export const CampaignHeader: React.FC<CampaignHeaderProps> = ({
// Proceed with status change
await performStatusUpdate(active);
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[campaign, triggersResponse?.content?.length],
);
diff --git a/src/pages/marketing/components/CampaignParticipantsTab.tsx b/src/pages/marketing/components/CampaignParticipantsTab.tsx
index 84d5218d..553e8f4d 100644
--- a/src/pages/marketing/components/CampaignParticipantsTab.tsx
+++ b/src/pages/marketing/components/CampaignParticipantsTab.tsx
@@ -12,11 +12,10 @@ import { useToast } from "@/components/ui/use-toast";
import { useDebouncedCallback } from "@tanstack/react-pacer";
import { captureException } from "config/sentry/TransformitySentry";
import { Activity, Eye, Users } from "lucide-react";
-import type React from "react";
-import { useCallback, useEffect, useRef, useState } from "react";
+import React, { useCallback, useEffect, useRef, useState } from "react";
import {
CustomerFilterForm,
- type CustomerFilterFormRef,
+ CustomerFilterFormRef,
CustomerList,
} from "src/components/CustomerFilter";
import { CsvParticipantUpload } from "src/components/marketing/CsvParticipantUpload";
@@ -27,11 +26,11 @@ import {
useGetCustomerFilter,
useUpdateCampaign,
} from "src/spring-generated/hooks";
-import type { Campaign } from "src/spring-generated/types";
+import { Campaign } from "src/spring-generated/types";
import { CustomerFilterSummary } from "./shared/CustomerFilterDisplay";
import {
CustomerSelectionModeSelector,
- type SelectionMode,
+ SelectionMode,
} from "./shared/CustomerSelectionModeSelector";
interface CampaignParticipantsTabProps {
@@ -48,9 +47,10 @@ export const CampaignParticipantsTab: React.FC<
const [selectionMode, setSelectionMode] = useState<SelectionMode>("all");
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const customerFilterFormRef = useRef<CustomerFilterFormRef>(null);
- const debouncedOnCampaignUpdate = useDebouncedCallback(onCampaignUpdate, {
- wait: 1000,
- });
+ const debouncedOnCampaignUpdate = useDebouncedCallback(
+ onCampaignUpdate,
+ 1000,
+ );
// Use custom hook for participant management
const {
@@ -73,13 +73,14 @@ export const CampaignParticipantsTab: React.FC<
const updateCampaignMutation = useUpdateCampaign();
// Use shared filter management hook
- const { handleFormSubmit } = useCampaignFilterManagement({
- campaignId: campaign?.id,
- onFilterSaved: () => {
- setIsEditingFilter(false);
- },
- onCampaignUpdate,
- });
+ const { handleFilterSave, handleFormSubmit, isUpdatingCampaign } =
+ useCampaignFilterManagement({
+ campaignId: campaign?.id,
+ onFilterSaved: () => {
+ setIsEditingFilter(false);
+ },
+ onCampaignUpdate,
+ });
// Determine current selection mode based on campaign state
const getCurrentMode = useCallback((): SelectionMode => {
diff --git a/src/pages/marketing/components/conditions/ConditionFormDialog.tsx b/src/pages/marketing/components/conditions/ConditionFormDialog.tsx
index 511788a3..b04c048e 100644
--- a/src/pages/marketing/components/conditions/ConditionFormDialog.tsx
+++ b/src/pages/marketing/components/conditions/ConditionFormDialog.tsx
@@ -60,9 +60,7 @@ export const ConditionFormDialog: React.FC<ConditionDialogProps> = ({
},
});
- const { reset, handleSubmit, trigger } = form;
-
- console.log(form.formState.errors);
+ const { reset, handleSubmit } = form;
// Reset form when dialog opens/closes or initial condition changes
useEffect(() => {
@@ -71,8 +69,6 @@ export const ConditionFormDialog: React.FC<ConditionDialogProps> = ({
// Transform existing condition to form format
const formData = transformFromCondition(initialCondition);
reset(formData as ConditionFormData);
- // Trigger validation after reset to ensure form state is updated
- void trigger();
} else {
// Set defaults for new condition
const type = allowedTypes[0];
@@ -133,7 +129,7 @@ export const ConditionFormDialog: React.FC<ConditionDialogProps> = ({
});
}
}
- }, [open, initialCondition, allowedTypes, reset, trigger]);
+ }, [open, initialCondition, allowedTypes, reset]);
const onSubmit = async (data: ConditionFormData) => {
try {
diff --git a/src/pages/paymentProcessor/PaymentProcessorReportsPage.tsx b/src/pages/paymentProcessor/PaymentProcessorReportsPage.tsx
index 40c4dd6c..3b10c93f 100644
--- a/src/pages/paymentProcessor/PaymentProcessorReportsPage.tsx
+++ b/src/pages/paymentProcessor/PaymentProcessorReportsPage.tsx
@@ -13,7 +13,7 @@ const PaymentProcessorReportsPage = () => {
const { value: feeReportEnabled } = useEntityConfig(
EntityConfigKey.FEE_REPORT,
- true,
+ false,
entity.id,
);
diff --git a/src/pages/report/SalesByTimeReport.tsx b/src/pages/report/SalesByTimeReport.tsx
index d0400eed..3ed4d00f 100644
--- a/src/pages/report/SalesByTimeReport.tsx
+++ b/src/pages/report/SalesByTimeReport.tsx
@@ -179,7 +179,6 @@ const SalesByTimeReport: React.FC<SalesByTimeReportProps> = ({
to: end,
});
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [start, end]);
const { data, isFetching } = useGetSalesByTimeIntervalChanged({
diff --git a/src/pages/report/TotalsReport/TotalsReportPage.tsx b/src/pages/report/TotalsReport/TotalsReportPage.tsx
index e2d55cce..45f13c5d 100644
--- a/src/pages/report/TotalsReport/TotalsReportPage.tsx
+++ b/src/pages/report/TotalsReport/TotalsReportPage.tsx
@@ -200,7 +200,6 @@ const TotalsReportPage = () => {
useEffect(() => {
void onSearch();
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [entitySelectedId]);
// Reset hasSearched when search params change (but not for preset clicks)
diff --git a/src/pages/shelftalker/tasks/CreateShelfTalkerTaskDialog.tsx b/src/pages/shelftalker/tasks/CreateShelfTalkerTaskDialog.tsx
index 646eaee0..aa02156e 100644
--- a/src/pages/shelftalker/tasks/CreateShelfTalkerTaskDialog.tsx
+++ b/src/pages/shelftalker/tasks/CreateShelfTalkerTaskDialog.tsx
@@ -82,7 +82,6 @@ export function CreateShelfTalkerTaskDialog({
setStep("completed");
await onTaskComplete?.();
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
[toast, queryClient],
);
diff --git a/src/phoenix-generated/clients/createWebsocketConnection.ts b/src/phoenix-generated/clients/createWebsocketConnection.ts
deleted file mode 100644
index 1b034468..00000000
--- a/src/phoenix-generated/clients/createWebsocketConnection.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { ResponseConfig } from "../../config/phoenix-client";
-import client from "../../config/phoenix-client";
-import type {
- CreateWebsocketConnectionMutationRequest,
- CreateWebsocketConnectionMutationResponse,
-} from "../types/CreateWebsocketConnection";
-
-/**
- * @description Create a websocket connection
- * @summary Create a websocket connection
- * @link /websocket/connection
- */
-export async function createWebsocketConnection(
- data: CreateWebsocketConnectionMutationRequest,
- options: Partial<Parameters<typeof client>[0]> = {},
-): Promise<ResponseConfig<CreateWebsocketConnectionMutationResponse>["data"]> {
- const res = await client<
- CreateWebsocketConnectionMutationResponse,
- CreateWebsocketConnectionMutationRequest
- >({ method: "post", url: `/websocket/connection`, data, ...options });
- return res.data;
-}
diff --git a/src/phoenix-generated/clients/getTransactionByTransactionItem.ts b/src/phoenix-generated/clients/getTransactionByTransactionItem.ts
deleted file mode 100644
index 72752598..00000000
--- a/src/phoenix-generated/clients/getTransactionByTransactionItem.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { ResponseConfig } from "../../config/phoenix-client";
-import client from "../../config/phoenix-client";
-import type {
- GetTransactionByTransactionItemPathParams,
- GetTransactionByTransactionItemQueryResponse,
-} from "../types/GetTransactionByTransactionItem";
-
-/**
- * @description Get transaction by transaction item ID
- * @summary Get transaction by transaction item
- * @link /transaction/transaction-item/:id
- */
-export async function getTransactionByTransactionItem(
- id: GetTransactionByTransactionItemPathParams["id"],
- options: Partial<Parameters<typeof client>[0]> = {},
-): Promise<
- ResponseConfig<GetTransactionByTransactionItemQueryResponse>["data"]
-> {
- const res = await client<GetTransactionByTransactionItemQueryResponse>({
- method: "get",
- url: `/transaction/transaction-item/${id}`,
- ...options,
- });
- return res.data;
-}
diff --git a/src/phoenix-generated/clients/index.ts b/src/phoenix-generated/clients/index.ts
deleted file mode 100644
index bf4fa97d..00000000
--- a/src/phoenix-generated/clients/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from "./createWebsocketConnection";
-export * from "./getTransactionByTransactionItem";
-export * from "./removeWebsocketConnection";
-export * from "./updateOrderItemDecisionStatus";
diff --git a/src/phoenix-generated/clients/operations.ts b/src/phoenix-generated/clients/operations.ts
deleted file mode 100644
index 1f18c76e..00000000
--- a/src/phoenix-generated/clients/operations.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export const operations = {
- updateOrderItemDecisionStatus: {
- path: "/order-item-decisions/:id/status",
- method: "put",
- },
- getTransactionByTransactionItem: {
- path: "/transaction/transaction-item/:id",
- method: "get",
- },
- createWebsocketConnection: {
- path: "/websocket/connection",
- method: "post",
- },
- removeWebsocketConnection: {
- path: "/websocket/connection/:connectionID",
- method: "delete",
- },
-} as const;
diff --git a/src/phoenix-generated/clients/removeWebsocketConnection.ts b/src/phoenix-generated/clients/removeWebsocketConnection.ts
deleted file mode 100644
index 7175eca9..00000000
--- a/src/phoenix-generated/clients/removeWebsocketConnection.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import type { ResponseConfig } from "../../config/phoenix-client";
-import client from "../../config/phoenix-client";
-import type {
- RemoveWebsocketConnectionMutationResponse,
- RemoveWebsocketConnectionPathParams,
-} from "../types/RemoveWebsocketConnection";
-
-/**
- * @description Delete a websocket connection
- * @summary Delete a websocket connection
- * @link /websocket/connection/:connectionID
- */
-export async function removeWebsocketConnection(
- connectionId: RemoveWebsocketConnectionPathParams["connectionID"],
- options: Partial<Parameters<typeof client>[0]> = {},
-): Promise<ResponseConfig<RemoveWebsocketConnectionMutationResponse>["data"]> {
- const res = await client<RemoveWebsocketConnectionMutationResponse>({
- method: "delete",
- url: `/websocket/connection/${connectionId}`,
- ...options,
- });
- return res.data;
-}
diff --git a/src/phoenix-generated/clients/updateOrderItemDecisionStatus.ts b/src/phoenix-generated/clients/updateOrderItemDecisionStatus.ts
deleted file mode 100644
index 943af6c5..00000000
--- a/src/phoenix-generated/clients/updateOrderItemDecisionStatus.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import type { ResponseConfig } from "../../config/phoenix-client";
-import client from "../../config/phoenix-client";
-import type {
- UpdateOrderItemDecisionStatusMutationRequest,
- UpdateOrderItemDecisionStatusMutationResponse,
- UpdateOrderItemDecisionStatusPathParams,
-} from "../types/UpdateOrderItemDecisionStatus";
-
-/**
- * @description Update the status of an order item decision
- * @summary Update order item decision status
- * @link /order-item-decisions/:id/status
- */
-export async function updateOrderItemDecisionStatus(
- id: UpdateOrderItemDecisionStatusPathParams["id"],
- data: UpdateOrderItemDecisionStatusMutationRequest,
- options: Partial<Parameters<typeof client>[0]> = {},
-): Promise<
- ResponseConfig<UpdateOrderItemDecisionStatusMutationResponse>["data"]
-> {
- const res = await client<
- UpdateOrderItemDecisionStatusMutationResponse,
- UpdateOrderItemDecisionStatusMutationRequest
- >({
- method: "put",
- url: `/order-item-decisions/${id}/status`,
- data,
- ...options,
- });
- return res.data;
-}
diff --git a/src/phoenix-generated/hooks/index.ts b/src/phoenix-generated/hooks/index.ts
deleted file mode 100644
index e60f5e3d..00000000
--- a/src/phoenix-generated/hooks/index.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-export * from "./useCreateLoyaltyCustomerMessage";
-export * from "./useCreateOrderItemDecision";
-export * from "./useCreateWebsocketConnection";
-export * from "./useDeleteFulfillmentId";
-export * from "./useDeleteOrderItemDecisionsId";
-export * from "./useDeleteStorefrontPagesPageid";
-export * from "./useDeleteStoreHoursEntitySalesChannelEntitySalesChannelId";
-export * from "./useGet";
-export * from "./useGetCategories";
-export * from "./useGetCategoriesHierarchy";
-export * from "./useGetCustomerId";
-export * from "./useGetEntityId";
-export * from "./useGetFulfillment";
-export * from "./useGetFulfillmentOrderItemOrderItemId";
-export * from "./useGetHealth";
-export * from "./useGetLoyaltyCustomer";
-export * from "./useGetLoyaltyCustomerIdPoints";
-export * from "./useGetOrderItemDecision";
-export * from "./useGetOrderItemDecisionsTransactionItemTransactionItemId";
-export * from "./useGetProducts";
-export * from "./useGetProductsProductId";
-export * from "./useGetProductsStorefrontStorefrontIdPathPath";
-export * from "./useGetStorefrontPagesPageid";
-export * from "./useGetStorefrontsCustomDomainCustomDomain";
-export * from "./useGetStorefrontsId";
-export * from "./useGetStorefrontsIdPages";
-export * from "./useGetStorefrontsSubdomainSubdomain";
-export * from "./useGetStorefrontsSubdomainSubdomainCheck";
-export * from "./useGetStorefrontsSubdomainSubdomainPagesPath";
-export * from "./useGetStoreHoursEntitySalesChannelEntitySalesChannelId";
-export * from "./useGetTransactionByTransactionItem";
-export * from "./useGetTransactionId";
-export * from "./useGetTransactionItemId";
-export * from "./useGetWebsocketConnections";
-export * from "./useGetWebsocketMessage";
-export * from "./useListFulfillments";
-export * from "./useListLoyaltyCustomers";
-export * from "./useListOrderItemDecisions";
-export * from "./useListStorefronts";
-export * from "./useListTransactionItems";
-export * from "./useListTransactions";
-export * from "./usePatchFulfillmentId";
-export * from "./usePatchStorefrontsId";
-export * from "./usePostCustomer";
-export * from "./usePostFulfillment";
-export * from "./usePostLoyaltyCustomer";
-export * from "./usePostStorefronts";
-export * from "./usePostStorefrontsIdAssetsPresignedUrl";
-export * from "./usePostStorefrontsIdPages";
-export * from "./usePostStoreHoursEntitySalesChannelEntitySalesChannelId";
-export * from "./usePutCustomer";
-export * from "./usePutStorefrontPagesPageid";
-export * from "./usePutStoreHoursEntitySalesChannelEntitySalesChannelId";
-export * from "./useRemoveWebsocketConnection";
-export * from "./useUpdateOrderItemDecisionStatus";
diff --git a/src/phoenix-generated/hooks/useCreateLoyaltyCustomerMessage.ts b/src/phoenix-generated/hooks/useCreateLoyaltyCustomerMessage.ts
deleted file mode 100644
index 173f678a..00000000
--- a/src/phoenix-generated/hooks/useCreateLoyaltyCustomerMessage.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- CreateLoyaltyCustomerMessage400,
- CreateLoyaltyCustomerMessage401,
- CreateLoyaltyCustomerMessage422,
- CreateLoyaltyCustomerMessage500,
- CreateLoyaltyCustomerMessageMutationRequest,
- CreateLoyaltyCustomerMessageMutationResponse,
-} from "../types/CreateLoyaltyCustomerMessage";
-
-type CreateLoyaltyCustomerMessageClient = typeof client<
- CreateLoyaltyCustomerMessageMutationResponse,
- | CreateLoyaltyCustomerMessage400
- | CreateLoyaltyCustomerMessage401
- | CreateLoyaltyCustomerMessage422
- | CreateLoyaltyCustomerMessage500,
- CreateLoyaltyCustomerMessageMutationRequest
->;
-type CreateLoyaltyCustomerMessage = {
- data: CreateLoyaltyCustomerMessageMutationResponse;
- error:
- | CreateLoyaltyCustomerMessage400
- | CreateLoyaltyCustomerMessage401
- | CreateLoyaltyCustomerMessage422
- | CreateLoyaltyCustomerMessage500;
- request: CreateLoyaltyCustomerMessageMutationRequest;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: CreateLoyaltyCustomerMessageMutationResponse;
- client: {
- parameters: Partial<Parameters<CreateLoyaltyCustomerMessageClient>[0]>;
- return: Awaited<ReturnType<CreateLoyaltyCustomerMessageClient>>;
- };
-};
-/**
- * @description Create a new loyalty customer message
- * @summary Create loyalty customer message
- * @link /loyalty-customer/message
- */
-export function useCreateLoyaltyCustomerMessage(
- options: {
- mutation?: UseMutationOptions<
- CreateLoyaltyCustomerMessage["response"],
- CreateLoyaltyCustomerMessage["error"],
- {
- data: CreateLoyaltyCustomerMessage["request"];
- }
- >;
- client?: CreateLoyaltyCustomerMessage["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ data }) => {
- const res = await client<
- CreateLoyaltyCustomerMessage["data"],
- CreateLoyaltyCustomerMessage["error"],
- CreateLoyaltyCustomerMessage["request"]
- >({
- method: "post",
- url: `/loyalty-customer/message`,
- data,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useCreateOrderItemDecision.ts b/src/phoenix-generated/hooks/useCreateOrderItemDecision.ts
deleted file mode 100644
index e3087bbd..00000000
--- a/src/phoenix-generated/hooks/useCreateOrderItemDecision.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- CreateOrderItemDecision400,
- CreateOrderItemDecision401,
- CreateOrderItemDecision422,
- CreateOrderItemDecision500,
- CreateOrderItemDecisionMutationRequest,
- CreateOrderItemDecisionMutationResponse,
-} from "../types/CreateOrderItemDecision";
-
-type CreateOrderItemDecisionClient = typeof client<
- CreateOrderItemDecisionMutationResponse,
- | CreateOrderItemDecision400
- | CreateOrderItemDecision401
- | CreateOrderItemDecision422
- | CreateOrderItemDecision500,
- CreateOrderItemDecisionMutationRequest
->;
-type CreateOrderItemDecision = {
- data: CreateOrderItemDecisionMutationResponse;
- error:
- | CreateOrderItemDecision400
- | CreateOrderItemDecision401
- | CreateOrderItemDecision422
- | CreateOrderItemDecision500;
- request: CreateOrderItemDecisionMutationRequest;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: CreateOrderItemDecisionMutationResponse;
- client: {
- parameters: Partial<Parameters<CreateOrderItemDecisionClient>[0]>;
- return: Awaited<ReturnType<CreateOrderItemDecisionClient>>;
- };
-};
-/**
- * @description Create a new order item decision
- * @summary Create order item decision
- * @link /order-item-decisions
- */
-export function useCreateOrderItemDecision(
- options: {
- mutation?: UseMutationOptions<
- CreateOrderItemDecision["response"],
- CreateOrderItemDecision["error"],
- {
- data: CreateOrderItemDecision["request"];
- }
- >;
- client?: CreateOrderItemDecision["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ data }) => {
- const res = await client<
- CreateOrderItemDecision["data"],
- CreateOrderItemDecision["error"],
- CreateOrderItemDecision["request"]
- >({
- method: "post",
- url: `/order-item-decisions`,
- data,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useCreateWebsocketConnection.ts b/src/phoenix-generated/hooks/useCreateWebsocketConnection.ts
deleted file mode 100644
index 72c086e2..00000000
--- a/src/phoenix-generated/hooks/useCreateWebsocketConnection.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- CreateWebsocketConnection400,
- CreateWebsocketConnection401,
- CreateWebsocketConnection500,
- CreateWebsocketConnectionMutationRequest,
- CreateWebsocketConnectionMutationResponse,
-} from "../types/CreateWebsocketConnection";
-
-type CreateWebsocketConnectionClient = typeof client<
- CreateWebsocketConnectionMutationResponse,
- | CreateWebsocketConnection400
- | CreateWebsocketConnection401
- | CreateWebsocketConnection500,
- CreateWebsocketConnectionMutationRequest
->;
-type CreateWebsocketConnection = {
- data: CreateWebsocketConnectionMutationResponse;
- error:
- | CreateWebsocketConnection400
- | CreateWebsocketConnection401
- | CreateWebsocketConnection500;
- request: CreateWebsocketConnectionMutationRequest;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: CreateWebsocketConnectionMutationResponse;
- client: {
- parameters: Partial<Parameters<CreateWebsocketConnectionClient>[0]>;
- return: Awaited<ReturnType<CreateWebsocketConnectionClient>>;
- };
-};
-/**
- * @description Create a websocket connection
- * @summary Create a websocket connection
- * @link /websocket/connection
- */
-export function useCreateWebsocketConnection(
- options: {
- mutation?: UseMutationOptions<
- CreateWebsocketConnection["response"],
- CreateWebsocketConnection["error"],
- {
- data: CreateWebsocketConnection["request"];
- }
- >;
- client?: CreateWebsocketConnection["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ data }) => {
- const res = await client<
- CreateWebsocketConnection["data"],
- CreateWebsocketConnection["error"],
- CreateWebsocketConnection["request"]
- >({
- method: "post",
- url: `/websocket/connection`,
- data,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useDeleteFulfillmentId.ts b/src/phoenix-generated/hooks/useDeleteFulfillmentId.ts
deleted file mode 100644
index d5ef28f4..00000000
--- a/src/phoenix-generated/hooks/useDeleteFulfillmentId.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- DeleteFulfillmentId400,
- DeleteFulfillmentId401,
- DeleteFulfillmentId404,
- DeleteFulfillmentId500,
- DeleteFulfillmentIdMutationResponse,
- DeleteFulfillmentIdPathParams,
-} from "../types/DeleteFulfillmentId";
-
-type DeleteFulfillmentIdClient = typeof client<
- DeleteFulfillmentIdMutationResponse,
- | DeleteFulfillmentId400
- | DeleteFulfillmentId401
- | DeleteFulfillmentId404
- | DeleteFulfillmentId500,
- never
->;
-type DeleteFulfillmentId = {
- data: DeleteFulfillmentIdMutationResponse;
- error:
- | DeleteFulfillmentId400
- | DeleteFulfillmentId401
- | DeleteFulfillmentId404
- | DeleteFulfillmentId500;
- request: never;
- pathParams: DeleteFulfillmentIdPathParams;
- queryParams: never;
- headerParams: never;
- response: DeleteFulfillmentIdMutationResponse;
- client: {
- parameters: Partial<Parameters<DeleteFulfillmentIdClient>[0]>;
- return: Awaited<ReturnType<DeleteFulfillmentIdClient>>;
- };
-};
-/**
- * @description Delete a fulfillment by ID
- * @summary Delete fulfillment
- * @link /fulfillment/:id
- */
-export function useDeleteFulfillmentId(
- options: {
- mutation?: UseMutationOptions<
- DeleteFulfillmentId["response"],
- DeleteFulfillmentId["error"],
- {
- id: DeleteFulfillmentIdPathParams["id"];
- }
- >;
- client?: DeleteFulfillmentId["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ id }) => {
- const res = await client<
- DeleteFulfillmentId["data"],
- DeleteFulfillmentId["error"],
- DeleteFulfillmentId["request"]
- >({
- method: "delete",
- url: `/fulfillment/${id}`,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useDeleteOrderItemDecisionsId.ts b/src/phoenix-generated/hooks/useDeleteOrderItemDecisionsId.ts
deleted file mode 100644
index e91a46ed..00000000
--- a/src/phoenix-generated/hooks/useDeleteOrderItemDecisionsId.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- DeleteOrderItemDecisionsId400,
- DeleteOrderItemDecisionsId401,
- DeleteOrderItemDecisionsId404,
- DeleteOrderItemDecisionsId500,
- DeleteOrderItemDecisionsIdMutationResponse,
- DeleteOrderItemDecisionsIdPathParams,
-} from "../types/DeleteOrderItemDecisionsId";
-
-type DeleteOrderItemDecisionsIdClient = typeof client<
- DeleteOrderItemDecisionsIdMutationResponse,
- | DeleteOrderItemDecisionsId400
- | DeleteOrderItemDecisionsId401
- | DeleteOrderItemDecisionsId404
- | DeleteOrderItemDecisionsId500,
- never
->;
-type DeleteOrderItemDecisionsId = {
- data: DeleteOrderItemDecisionsIdMutationResponse;
- error:
- | DeleteOrderItemDecisionsId400
- | DeleteOrderItemDecisionsId401
- | DeleteOrderItemDecisionsId404
- | DeleteOrderItemDecisionsId500;
- request: never;
- pathParams: DeleteOrderItemDecisionsIdPathParams;
- queryParams: never;
- headerParams: never;
- response: DeleteOrderItemDecisionsIdMutationResponse;
- client: {
- parameters: Partial<Parameters<DeleteOrderItemDecisionsIdClient>[0]>;
- return: Awaited<ReturnType<DeleteOrderItemDecisionsIdClient>>;
- };
-};
-/**
- * @description Delete an order item decision
- * @summary Delete order item decision
- * @link /order-item-decisions/:id
- */
-export function useDeleteOrderItemDecisionsId(
- options: {
- mutation?: UseMutationOptions<
- DeleteOrderItemDecisionsId["response"],
- DeleteOrderItemDecisionsId["error"],
- {
- id: DeleteOrderItemDecisionsIdPathParams["id"];
- }
- >;
- client?: DeleteOrderItemDecisionsId["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ id }) => {
- const res = await client<
- DeleteOrderItemDecisionsId["data"],
- DeleteOrderItemDecisionsId["error"],
- DeleteOrderItemDecisionsId["request"]
- >({
- method: "delete",
- url: `/order-item-decisions/${id}`,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useDeleteStoreHoursEntitySalesChannelEntitySalesChannelId.ts b/src/phoenix-generated/hooks/useDeleteStoreHoursEntitySalesChannelEntitySalesChannelId.ts
deleted file mode 100644
index ee5d160c..00000000
--- a/src/phoenix-generated/hooks/useDeleteStoreHoursEntitySalesChannelEntitySalesChannelId.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId400,
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId500,
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdMutationResponse,
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams,
-} from "../types/DeleteStoreHoursEntitySalesChannelEntitySalesChannelId";
-
-type DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdClient =
- typeof client<
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdMutationResponse,
- | DeleteStoreHoursEntitySalesChannelEntitySalesChannelId400
- | DeleteStoreHoursEntitySalesChannelEntitySalesChannelId500,
- never
- >;
-type DeleteStoreHoursEntitySalesChannelEntitySalesChannelId = {
- data: DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdMutationResponse;
- error:
- | DeleteStoreHoursEntitySalesChannelEntitySalesChannelId400
- | DeleteStoreHoursEntitySalesChannelEntitySalesChannelId500;
- request: never;
- pathParams: DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams;
- queryParams: never;
- headerParams: never;
- response: DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdMutationResponse;
- client: {
- parameters: Partial<
- Parameters<DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdClient>[0]
- >;
- return: Awaited<
- ReturnType<DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdClient>
- >;
- };
-};
-/**
- * @description Delete all store hours for an entity sales channel
- * @summary Delete store hours for entity sales channel
- * @link /store-hours/entity-sales-channel/:entity_sales_channel_id
- */
-export function useDeleteStoreHoursEntitySalesChannelEntitySalesChannelId(
- options: {
- mutation?: UseMutationOptions<
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["error"],
- {
- entitySalesChannelId: DeleteStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"];
- }
- >;
- client?: DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ entitySalesChannelId }) => {
- const res = await client<
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["data"],
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["error"],
- DeleteStoreHoursEntitySalesChannelEntitySalesChannelId["request"]
- >({
- method: "delete",
- url: `/store-hours/entity-sales-channel/${entitySalesChannelId}`,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useDeleteStorefrontPagesPageid.ts b/src/phoenix-generated/hooks/useDeleteStorefrontPagesPageid.ts
deleted file mode 100644
index dc45871c..00000000
--- a/src/phoenix-generated/hooks/useDeleteStorefrontPagesPageid.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- DeleteStorefrontPagesPageid400,
- DeleteStorefrontPagesPageid401,
- DeleteStorefrontPagesPageid404,
- DeleteStorefrontPagesPageid500,
- DeleteStorefrontPagesPageidMutationResponse,
- DeleteStorefrontPagesPageidPathParams,
-} from "../types/DeleteStorefrontPagesPageid";
-
-type DeleteStorefrontPagesPageidClient = typeof client<
- DeleteStorefrontPagesPageidMutationResponse,
- | DeleteStorefrontPagesPageid400
- | DeleteStorefrontPagesPageid401
- | DeleteStorefrontPagesPageid404
- | DeleteStorefrontPagesPageid500,
- never
->;
-type DeleteStorefrontPagesPageid = {
- data: DeleteStorefrontPagesPageidMutationResponse;
- error:
- | DeleteStorefrontPagesPageid400
- | DeleteStorefrontPagesPageid401
- | DeleteStorefrontPagesPageid404
- | DeleteStorefrontPagesPageid500;
- request: never;
- pathParams: DeleteStorefrontPagesPageidPathParams;
- queryParams: never;
- headerParams: never;
- response: DeleteStorefrontPagesPageidMutationResponse;
- client: {
- parameters: Partial<Parameters<DeleteStorefrontPagesPageidClient>[0]>;
- return: Awaited<ReturnType<DeleteStorefrontPagesPageidClient>>;
- };
-};
-/**
- * @description Delete a storefront page by its ID
- * @summary Delete storefront page
- * @link /storefront-pages/:pageId
- */
-export function useDeleteStorefrontPagesPageid(
- options: {
- mutation?: UseMutationOptions<
- DeleteStorefrontPagesPageid["response"],
- DeleteStorefrontPagesPageid["error"],
- {
- pageId: DeleteStorefrontPagesPageidPathParams["pageId"];
- }
- >;
- client?: DeleteStorefrontPagesPageid["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ pageId }) => {
- const res = await client<
- DeleteStorefrontPagesPageid["data"],
- DeleteStorefrontPagesPageid["error"],
- DeleteStorefrontPagesPageid["request"]
- >({
- method: "delete",
- url: `/storefront-pages/${pageId}`,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/useGet.ts b/src/phoenix-generated/hooks/useGet.ts
deleted file mode 100644
index 4dc61234..00000000
--- a/src/phoenix-generated/hooks/useGet.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type { GetQueryResponse } from "../types/Get";
-
-type GetClient = typeof client<GetQueryResponse, Error, never>;
-type Get = {
- data: GetQueryResponse;
- error: Error;
- request: never;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: GetQueryResponse;
- client: {
- parameters: Partial<Parameters<GetClient>[0]>;
- return: Awaited<ReturnType<GetClient>>;
- };
-};
-export const getQueryKey = () => [{ url: "/" }] as const;
-export type GetQueryKey = ReturnType<typeof getQueryKey>;
-export function getQueryOptions(options: Get["client"]["parameters"] = {}) {
- const queryKey = getQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<Get["data"], Get["error"]>({
- method: "get",
- url: `/`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Returns a welcome message
- * @summary Get welcome message
- * @link /
- */
-export function useGet<
- TData = Get["response"],
- TQueryData = Get["response"],
- TQueryKey extends QueryKey = GetQueryKey,
->(
- options: {
- query?: Partial<
- QueryObserverOptions<
- Get["response"],
- Get["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: Get["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, Get["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getQueryKey();
- const query = useQuery({
- ...(getQueryOptions(clientOptions) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, Get["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getSuspenseQueryKey = () => [{ url: "/" }] as const;
-export type GetSuspenseQueryKey = ReturnType<typeof getSuspenseQueryKey>;
-export function getSuspenseQueryOptions(
- options: Get["client"]["parameters"] = {},
-) {
- const queryKey = getSuspenseQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<Get["data"], Get["error"]>({
- method: "get",
- url: `/`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Returns a welcome message
- * @summary Get welcome message
- * @link /
- */
-export function useGetSuspense<
- TData = Get["response"],
- TQueryKey extends QueryKey = GetSuspenseQueryKey,
->(
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<Get["response"], Get["error"], TData, TQueryKey>
- >;
- client?: Get["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, Get["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getSuspenseQueryKey();
- const query = useSuspenseQuery({
- ...(getSuspenseQueryOptions(
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, Get["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetCategories.ts b/src/phoenix-generated/hooks/useGetCategories.ts
deleted file mode 100644
index b5f6ef80..00000000
--- a/src/phoenix-generated/hooks/useGetCategories.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetCategories400,
- GetCategories401,
- GetCategories422,
- GetCategories500,
- GetCategoriesQueryParams,
- GetCategoriesQueryResponse,
-} from "../types/GetCategories";
-
-type GetCategoriesClient = typeof client<
- GetCategoriesQueryResponse,
- GetCategories400 | GetCategories401 | GetCategories422 | GetCategories500,
- never
->;
-type GetCategories = {
- data: GetCategoriesQueryResponse;
- error:
- | GetCategories400
- | GetCategories401
- | GetCategories422
- | GetCategories500;
- request: never;
- pathParams: never;
- queryParams: GetCategoriesQueryParams;
- headerParams: never;
- response: GetCategoriesQueryResponse;
- client: {
- parameters: Partial<Parameters<GetCategoriesClient>[0]>;
- return: Awaited<ReturnType<GetCategoriesClient>>;
- };
-};
-export const getCategoriesQueryKey = (params?: GetCategories["queryParams"]) =>
- [{ url: "/categories" }, ...(params ? [params] : [])] as const;
-export type GetCategoriesQueryKey = ReturnType<typeof getCategoriesQueryKey>;
-export function getCategoriesQueryOptions(
- params?: GetCategories["queryParams"],
- options: GetCategories["client"]["parameters"] = {},
-) {
- const queryKey = getCategoriesQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetCategories["data"], GetCategories["error"]>({
- method: "get",
- url: `/categories`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List categories with pagination and optional search
- * @summary List categories
- * @link /categories
- */
-export function useGetCategories<
- TData = GetCategories["response"],
- TQueryData = GetCategories["response"],
- TQueryKey extends QueryKey = GetCategoriesQueryKey,
->(
- params?: GetCategories["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetCategories["response"],
- GetCategories["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetCategories["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetCategories["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getCategoriesQueryKey(params);
- const query = useQuery({
- ...(getCategoriesQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetCategories["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getCategoriesSuspenseQueryKey = (
- params?: GetCategories["queryParams"],
-) => [{ url: "/categories" }, ...(params ? [params] : [])] as const;
-export type GetCategoriesSuspenseQueryKey = ReturnType<
- typeof getCategoriesSuspenseQueryKey
->;
-export function getCategoriesSuspenseQueryOptions(
- params?: GetCategories["queryParams"],
- options: GetCategories["client"]["parameters"] = {},
-) {
- const queryKey = getCategoriesSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetCategories["data"], GetCategories["error"]>({
- method: "get",
- url: `/categories`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List categories with pagination and optional search
- * @summary List categories
- * @link /categories
- */
-export function useGetCategoriesSuspense<
- TData = GetCategories["response"],
- TQueryKey extends QueryKey = GetCategoriesSuspenseQueryKey,
->(
- params?: GetCategories["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetCategories["response"],
- GetCategories["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetCategories["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetCategories["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getCategoriesSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(getCategoriesSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetCategories["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetCategoriesHierarchy.ts b/src/phoenix-generated/hooks/useGetCategoriesHierarchy.ts
deleted file mode 100644
index 9a03f42e..00000000
--- a/src/phoenix-generated/hooks/useGetCategoriesHierarchy.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetCategoriesHierarchy500,
- GetCategoriesHierarchyQueryResponse,
-} from "../types/GetCategoriesHierarchy";
-
-type GetCategoriesHierarchyClient = typeof client<
- GetCategoriesHierarchyQueryResponse,
- GetCategoriesHierarchy500,
- never
->;
-type GetCategoriesHierarchy = {
- data: GetCategoriesHierarchyQueryResponse;
- error: GetCategoriesHierarchy500;
- request: never;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: GetCategoriesHierarchyQueryResponse;
- client: {
- parameters: Partial<Parameters<GetCategoriesHierarchyClient>[0]>;
- return: Awaited<ReturnType<GetCategoriesHierarchyClient>>;
- };
-};
-export const getCategoriesHierarchyQueryKey = () =>
- [{ url: "/categories/hierarchy" }] as const;
-export type GetCategoriesHierarchyQueryKey = ReturnType<
- typeof getCategoriesHierarchyQueryKey
->;
-export function getCategoriesHierarchyQueryOptions(
- options: GetCategoriesHierarchy["client"]["parameters"] = {},
-) {
- const queryKey = getCategoriesHierarchyQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetCategoriesHierarchy["data"],
- GetCategoriesHierarchy["error"]
- >({
- method: "get",
- url: `/categories/hierarchy`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get all categories in a hierarchical structure with nested children
- * @summary Get categories hierarchy
- * @link /categories/hierarchy
- */
-export function useGetCategoriesHierarchy<
- TData = GetCategoriesHierarchy["response"],
- TQueryData = GetCategoriesHierarchy["response"],
- TQueryKey extends QueryKey = GetCategoriesHierarchyQueryKey,
->(
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetCategoriesHierarchy["response"],
- GetCategoriesHierarchy["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetCategoriesHierarchy["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetCategoriesHierarchy["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getCategoriesHierarchyQueryKey();
- const query = useQuery({
- ...(getCategoriesHierarchyQueryOptions(
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetCategoriesHierarchy["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getCategoriesHierarchySuspenseQueryKey = () =>
- [{ url: "/categories/hierarchy" }] as const;
-export type GetCategoriesHierarchySuspenseQueryKey = ReturnType<
- typeof getCategoriesHierarchySuspenseQueryKey
->;
-export function getCategoriesHierarchySuspenseQueryOptions(
- options: GetCategoriesHierarchy["client"]["parameters"] = {},
-) {
- const queryKey = getCategoriesHierarchySuspenseQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetCategoriesHierarchy["data"],
- GetCategoriesHierarchy["error"]
- >({
- method: "get",
- url: `/categories/hierarchy`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get all categories in a hierarchical structure with nested children
- * @summary Get categories hierarchy
- * @link /categories/hierarchy
- */
-export function useGetCategoriesHierarchySuspense<
- TData = GetCategoriesHierarchy["response"],
- TQueryKey extends QueryKey = GetCategoriesHierarchySuspenseQueryKey,
->(
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetCategoriesHierarchy["response"],
- GetCategoriesHierarchy["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetCategoriesHierarchy["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetCategoriesHierarchy["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getCategoriesHierarchySuspenseQueryKey();
- const query = useSuspenseQuery({
- ...(getCategoriesHierarchySuspenseQueryOptions(
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetCategoriesHierarchy["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetCustomerId.ts b/src/phoenix-generated/hooks/useGetCustomerId.ts
deleted file mode 100644
index 0b3058d3..00000000
--- a/src/phoenix-generated/hooks/useGetCustomerId.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetCustomerId400,
- GetCustomerId401,
- GetCustomerId404,
- GetCustomerId500,
- GetCustomerIdPathParams,
- GetCustomerIdQueryResponse,
-} from "../types/GetCustomerId";
-
-type GetCustomerIdClient = typeof client<
- GetCustomerIdQueryResponse,
- GetCustomerId400 | GetCustomerId401 | GetCustomerId404 | GetCustomerId500,
- never
->;
-type GetCustomerId = {
- data: GetCustomerIdQueryResponse;
- error:
- | GetCustomerId400
- | GetCustomerId401
- | GetCustomerId404
- | GetCustomerId500;
- request: never;
- pathParams: GetCustomerIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetCustomerIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetCustomerIdClient>[0]>;
- return: Awaited<ReturnType<GetCustomerIdClient>>;
- };
-};
-export const getCustomerIdQueryKey = (id: GetCustomerIdPathParams["id"]) =>
- [{ url: "/customer/:id", params: { id: id } }] as const;
-export type GetCustomerIdQueryKey = ReturnType<typeof getCustomerIdQueryKey>;
-export function getCustomerIdQueryOptions(
- id: GetCustomerIdPathParams["id"],
- options: GetCustomerId["client"]["parameters"] = {},
-) {
- const queryKey = getCustomerIdQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetCustomerId["data"], GetCustomerId["error"]>({
- method: "get",
- url: `/customer/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a customer
- * @summary Get customer
- * @link /customer/:id
- */
-export function useGetCustomerId<
- TData = GetCustomerId["response"],
- TQueryData = GetCustomerId["response"],
- TQueryKey extends QueryKey = GetCustomerIdQueryKey,
->(
- id: GetCustomerIdPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetCustomerId["response"],
- GetCustomerId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetCustomerId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetCustomerId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getCustomerIdQueryKey(id);
- const query = useQuery({
- ...(getCustomerIdQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetCustomerId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getCustomerIdSuspenseQueryKey = (
- id: GetCustomerIdPathParams["id"],
-) => [{ url: "/customer/:id", params: { id: id } }] as const;
-export type GetCustomerIdSuspenseQueryKey = ReturnType<
- typeof getCustomerIdSuspenseQueryKey
->;
-export function getCustomerIdSuspenseQueryOptions(
- id: GetCustomerIdPathParams["id"],
- options: GetCustomerId["client"]["parameters"] = {},
-) {
- const queryKey = getCustomerIdSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetCustomerId["data"], GetCustomerId["error"]>({
- method: "get",
- url: `/customer/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a customer
- * @summary Get customer
- * @link /customer/:id
- */
-export function useGetCustomerIdSuspense<
- TData = GetCustomerId["response"],
- TQueryKey extends QueryKey = GetCustomerIdSuspenseQueryKey,
->(
- id: GetCustomerIdPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetCustomerId["response"],
- GetCustomerId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetCustomerId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetCustomerId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getCustomerIdSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getCustomerIdSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetCustomerId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetEntityId.ts b/src/phoenix-generated/hooks/useGetEntityId.ts
deleted file mode 100644
index 1a6e9d84..00000000
--- a/src/phoenix-generated/hooks/useGetEntityId.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetEntityId400,
- GetEntityId401,
- GetEntityId404,
- GetEntityId500,
- GetEntityIdPathParams,
- GetEntityIdQueryResponse,
-} from "../types/GetEntityId";
-
-type GetEntityIdClient = typeof client<
- GetEntityIdQueryResponse,
- GetEntityId400 | GetEntityId401 | GetEntityId404 | GetEntityId500,
- never
->;
-type GetEntityId = {
- data: GetEntityIdQueryResponse;
- error: GetEntityId400 | GetEntityId401 | GetEntityId404 | GetEntityId500;
- request: never;
- pathParams: GetEntityIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetEntityIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetEntityIdClient>[0]>;
- return: Awaited<ReturnType<GetEntityIdClient>>;
- };
-};
-export const getEntityIdQueryKey = (id: GetEntityIdPathParams["id"]) =>
- [{ url: "/entity/:id", params: { id: id } }] as const;
-export type GetEntityIdQueryKey = ReturnType<typeof getEntityIdQueryKey>;
-export function getEntityIdQueryOptions(
- id: GetEntityIdPathParams["id"],
- options: GetEntityId["client"]["parameters"] = {},
-) {
- const queryKey = getEntityIdQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetEntityId["data"], GetEntityId["error"]>({
- method: "get",
- url: `/entity/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get entity by ID
- * @summary Get entity
- * @link /entity/:id
- */
-export function useGetEntityId<
- TData = GetEntityId["response"],
- TQueryData = GetEntityId["response"],
- TQueryKey extends QueryKey = GetEntityIdQueryKey,
->(
- id: GetEntityIdPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetEntityId["response"],
- GetEntityId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetEntityId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetEntityId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getEntityIdQueryKey(id);
- const query = useQuery({
- ...(getEntityIdQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetEntityId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getEntityIdSuspenseQueryKey = (id: GetEntityIdPathParams["id"]) =>
- [{ url: "/entity/:id", params: { id: id } }] as const;
-export type GetEntityIdSuspenseQueryKey = ReturnType<
- typeof getEntityIdSuspenseQueryKey
->;
-export function getEntityIdSuspenseQueryOptions(
- id: GetEntityIdPathParams["id"],
- options: GetEntityId["client"]["parameters"] = {},
-) {
- const queryKey = getEntityIdSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetEntityId["data"], GetEntityId["error"]>({
- method: "get",
- url: `/entity/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get entity by ID
- * @summary Get entity
- * @link /entity/:id
- */
-export function useGetEntityIdSuspense<
- TData = GetEntityId["response"],
- TQueryKey extends QueryKey = GetEntityIdSuspenseQueryKey,
->(
- id: GetEntityIdPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetEntityId["response"],
- GetEntityId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetEntityId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetEntityId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getEntityIdSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getEntityIdSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetEntityId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetFulfillment.ts b/src/phoenix-generated/hooks/useGetFulfillment.ts
deleted file mode 100644
index 542b9605..00000000
--- a/src/phoenix-generated/hooks/useGetFulfillment.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetFulfillment400,
- GetFulfillment401,
- GetFulfillment404,
- GetFulfillment500,
- GetFulfillmentPathParams,
- GetFulfillmentQueryResponse,
-} from "../types/GetFulfillment";
-
-type GetFulfillmentClient = typeof client<
- GetFulfillmentQueryResponse,
- GetFulfillment400 | GetFulfillment401 | GetFulfillment404 | GetFulfillment500,
- never
->;
-type GetFulfillment = {
- data: GetFulfillmentQueryResponse;
- error:
- | GetFulfillment400
- | GetFulfillment401
- | GetFulfillment404
- | GetFulfillment500;
- request: never;
- pathParams: GetFulfillmentPathParams;
- queryParams: never;
- headerParams: never;
- response: GetFulfillmentQueryResponse;
- client: {
- parameters: Partial<Parameters<GetFulfillmentClient>[0]>;
- return: Awaited<ReturnType<GetFulfillmentClient>>;
- };
-};
-export const getFulfillmentQueryKey = (id: GetFulfillmentPathParams["id"]) =>
- [{ url: "/fulfillment/:id", params: { id: id } }] as const;
-export type GetFulfillmentQueryKey = ReturnType<typeof getFulfillmentQueryKey>;
-export function getFulfillmentQueryOptions(
- id: GetFulfillmentPathParams["id"],
- options: GetFulfillment["client"]["parameters"] = {},
-) {
- const queryKey = getFulfillmentQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetFulfillment["data"], GetFulfillment["error"]>(
- {
- method: "get",
- url: `/fulfillment/${id}`,
- ...options,
- },
- );
- return res.data;
- },
- });
-}
-/**
- * @description Get fulfillment by ID
- * @summary Get fulfillment
- * @link /fulfillment/:id
- */
-export function useGetFulfillment<
- TData = GetFulfillment["response"],
- TQueryData = GetFulfillment["response"],
- TQueryKey extends QueryKey = GetFulfillmentQueryKey,
->(
- id: GetFulfillmentPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetFulfillment["response"],
- GetFulfillment["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetFulfillment["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetFulfillment["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getFulfillmentQueryKey(id);
- const query = useQuery({
- ...(getFulfillmentQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetFulfillment["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getFulfillmentSuspenseQueryKey = (
- id: GetFulfillmentPathParams["id"],
-) => [{ url: "/fulfillment/:id", params: { id: id } }] as const;
-export type GetFulfillmentSuspenseQueryKey = ReturnType<
- typeof getFulfillmentSuspenseQueryKey
->;
-export function getFulfillmentSuspenseQueryOptions(
- id: GetFulfillmentPathParams["id"],
- options: GetFulfillment["client"]["parameters"] = {},
-) {
- const queryKey = getFulfillmentSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetFulfillment["data"], GetFulfillment["error"]>(
- {
- method: "get",
- url: `/fulfillment/${id}`,
- ...options,
- },
- );
- return res.data;
- },
- });
-}
-/**
- * @description Get fulfillment by ID
- * @summary Get fulfillment
- * @link /fulfillment/:id
- */
-export function useGetFulfillmentSuspense<
- TData = GetFulfillment["response"],
- TQueryKey extends QueryKey = GetFulfillmentSuspenseQueryKey,
->(
- id: GetFulfillmentPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetFulfillment["response"],
- GetFulfillment["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetFulfillment["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetFulfillment["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getFulfillmentSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getFulfillmentSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetFulfillment["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetFulfillmentOrderItemOrderItemId.ts b/src/phoenix-generated/hooks/useGetFulfillmentOrderItemOrderItemId.ts
deleted file mode 100644
index 78a36c67..00000000
--- a/src/phoenix-generated/hooks/useGetFulfillmentOrderItemOrderItemId.ts
+++ /dev/null
@@ -1,205 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetFulfillmentOrderItemOrderItemId400,
- GetFulfillmentOrderItemOrderItemId401,
- GetFulfillmentOrderItemOrderItemId404,
- GetFulfillmentOrderItemOrderItemId500,
- GetFulfillmentOrderItemOrderItemIdPathParams,
- GetFulfillmentOrderItemOrderItemIdQueryResponse,
-} from "../types/GetFulfillmentOrderItemOrderItemId";
-
-type GetFulfillmentOrderItemOrderItemIdClient = typeof client<
- GetFulfillmentOrderItemOrderItemIdQueryResponse,
- | GetFulfillmentOrderItemOrderItemId400
- | GetFulfillmentOrderItemOrderItemId401
- | GetFulfillmentOrderItemOrderItemId404
- | GetFulfillmentOrderItemOrderItemId500,
- never
->;
-type GetFulfillmentOrderItemOrderItemId = {
- data: GetFulfillmentOrderItemOrderItemIdQueryResponse;
- error:
- | GetFulfillmentOrderItemOrderItemId400
- | GetFulfillmentOrderItemOrderItemId401
- | GetFulfillmentOrderItemOrderItemId404
- | GetFulfillmentOrderItemOrderItemId500;
- request: never;
- pathParams: GetFulfillmentOrderItemOrderItemIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetFulfillmentOrderItemOrderItemIdQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetFulfillmentOrderItemOrderItemIdClient>[0]
- >;
- return: Awaited<ReturnType<GetFulfillmentOrderItemOrderItemIdClient>>;
- };
-};
-export const getFulfillmentOrderItemOrderItemIdQueryKey = (
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
-) =>
- [
- {
- url: "/fulfillment/order-item/:order_item_id",
- params: { orderItemId: orderItemId },
- },
- ] as const;
-export type GetFulfillmentOrderItemOrderItemIdQueryKey = ReturnType<
- typeof getFulfillmentOrderItemOrderItemIdQueryKey
->;
-export function getFulfillmentOrderItemOrderItemIdQueryOptions(
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
- options: GetFulfillmentOrderItemOrderItemId["client"]["parameters"] = {},
-) {
- const queryKey = getFulfillmentOrderItemOrderItemIdQueryKey(orderItemId);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetFulfillmentOrderItemOrderItemId["data"],
- GetFulfillmentOrderItemOrderItemId["error"]
- >({
- method: "get",
- url: `/fulfillment/order-item/${orderItemId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get fulfillment by order item ID
- * @summary Get fulfillment by order item ID
- * @link /fulfillment/order-item/:order_item_id
- */
-export function useGetFulfillmentOrderItemOrderItemId<
- TData = GetFulfillmentOrderItemOrderItemId["response"],
- TQueryData = GetFulfillmentOrderItemOrderItemId["response"],
- TQueryKey extends QueryKey = GetFulfillmentOrderItemOrderItemIdQueryKey,
->(
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetFulfillmentOrderItemOrderItemId["response"],
- GetFulfillmentOrderItemOrderItemId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetFulfillmentOrderItemOrderItemId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetFulfillmentOrderItemOrderItemId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getFulfillmentOrderItemOrderItemIdQueryKey(orderItemId);
- const query = useQuery({
- ...(getFulfillmentOrderItemOrderItemIdQueryOptions(
- orderItemId,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetFulfillmentOrderItemOrderItemId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getFulfillmentOrderItemOrderItemIdSuspenseQueryKey = (
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
-) =>
- [
- {
- url: "/fulfillment/order-item/:order_item_id",
- params: { orderItemId: orderItemId },
- },
- ] as const;
-export type GetFulfillmentOrderItemOrderItemIdSuspenseQueryKey = ReturnType<
- typeof getFulfillmentOrderItemOrderItemIdSuspenseQueryKey
->;
-export function getFulfillmentOrderItemOrderItemIdSuspenseQueryOptions(
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
- options: GetFulfillmentOrderItemOrderItemId["client"]["parameters"] = {},
-) {
- const queryKey =
- getFulfillmentOrderItemOrderItemIdSuspenseQueryKey(orderItemId);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetFulfillmentOrderItemOrderItemId["data"],
- GetFulfillmentOrderItemOrderItemId["error"]
- >({
- method: "get",
- url: `/fulfillment/order-item/${orderItemId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get fulfillment by order item ID
- * @summary Get fulfillment by order item ID
- * @link /fulfillment/order-item/:order_item_id
- */
-export function useGetFulfillmentOrderItemOrderItemIdSuspense<
- TData = GetFulfillmentOrderItemOrderItemId["response"],
- TQueryKey extends
- QueryKey = GetFulfillmentOrderItemOrderItemIdSuspenseQueryKey,
->(
- orderItemId: GetFulfillmentOrderItemOrderItemIdPathParams["order_item_id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetFulfillmentOrderItemOrderItemId["response"],
- GetFulfillmentOrderItemOrderItemId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetFulfillmentOrderItemOrderItemId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetFulfillmentOrderItemOrderItemId["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getFulfillmentOrderItemOrderItemIdSuspenseQueryKey(orderItemId);
- const query = useSuspenseQuery({
- ...(getFulfillmentOrderItemOrderItemIdSuspenseQueryOptions(
- orderItemId,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetFulfillmentOrderItemOrderItemId["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetHealth.ts b/src/phoenix-generated/hooks/useGetHealth.ts
deleted file mode 100644
index 595c4cf2..00000000
--- a/src/phoenix-generated/hooks/useGetHealth.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type { GetHealthQueryResponse } from "../types/GetHealth";
-
-type GetHealthClient = typeof client<GetHealthQueryResponse, Error, never>;
-type GetHealth = {
- data: GetHealthQueryResponse;
- error: Error;
- request: never;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: GetHealthQueryResponse;
- client: {
- parameters: Partial<Parameters<GetHealthClient>[0]>;
- return: Awaited<ReturnType<GetHealthClient>>;
- };
-};
-export const getHealthQueryKey = () => [{ url: "/health" }] as const;
-export type GetHealthQueryKey = ReturnType<typeof getHealthQueryKey>;
-export function getHealthQueryOptions(
- options: GetHealth["client"]["parameters"] = {},
-) {
- const queryKey = getHealthQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetHealth["data"], GetHealth["error"]>({
- method: "get",
- url: `/health`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Returns the health status of the API
- * @summary Health check
- * @link /health
- */
-export function useGetHealth<
- TData = GetHealth["response"],
- TQueryData = GetHealth["response"],
- TQueryKey extends QueryKey = GetHealthQueryKey,
->(
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetHealth["response"],
- GetHealth["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetHealth["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetHealth["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getHealthQueryKey();
- const query = useQuery({
- ...(getHealthQueryOptions(
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetHealth["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getHealthSuspenseQueryKey = () => [{ url: "/health" }] as const;
-export type GetHealthSuspenseQueryKey = ReturnType<
- typeof getHealthSuspenseQueryKey
->;
-export function getHealthSuspenseQueryOptions(
- options: GetHealth["client"]["parameters"] = {},
-) {
- const queryKey = getHealthSuspenseQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetHealth["data"], GetHealth["error"]>({
- method: "get",
- url: `/health`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Returns the health status of the API
- * @summary Health check
- * @link /health
- */
-export function useGetHealthSuspense<
- TData = GetHealth["response"],
- TQueryKey extends QueryKey = GetHealthSuspenseQueryKey,
->(
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetHealth["response"],
- GetHealth["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetHealth["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetHealth["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getHealthSuspenseQueryKey();
- const query = useSuspenseQuery({
- ...(getHealthSuspenseQueryOptions(
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetHealth["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetLoyaltyCustomer.ts b/src/phoenix-generated/hooks/useGetLoyaltyCustomer.ts
deleted file mode 100644
index 6cb9cfa1..00000000
--- a/src/phoenix-generated/hooks/useGetLoyaltyCustomer.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetLoyaltyCustomer400,
- GetLoyaltyCustomer401,
- GetLoyaltyCustomer404,
- GetLoyaltyCustomer500,
- GetLoyaltyCustomerPathParams,
- GetLoyaltyCustomerQueryResponse,
-} from "../types/GetLoyaltyCustomer";
-
-type GetLoyaltyCustomerClient = typeof client<
- GetLoyaltyCustomerQueryResponse,
- | GetLoyaltyCustomer400
- | GetLoyaltyCustomer401
- | GetLoyaltyCustomer404
- | GetLoyaltyCustomer500,
- never
->;
-type GetLoyaltyCustomer = {
- data: GetLoyaltyCustomerQueryResponse;
- error:
- | GetLoyaltyCustomer400
- | GetLoyaltyCustomer401
- | GetLoyaltyCustomer404
- | GetLoyaltyCustomer500;
- request: never;
- pathParams: GetLoyaltyCustomerPathParams;
- queryParams: never;
- headerParams: never;
- response: GetLoyaltyCustomerQueryResponse;
- client: {
- parameters: Partial<Parameters<GetLoyaltyCustomerClient>[0]>;
- return: Awaited<ReturnType<GetLoyaltyCustomerClient>>;
- };
-};
-export const getLoyaltyCustomerQueryKey = (
- id: GetLoyaltyCustomerPathParams["id"],
-) => [{ url: "/loyalty-customer/:id", params: { id: id } }] as const;
-export type GetLoyaltyCustomerQueryKey = ReturnType<
- typeof getLoyaltyCustomerQueryKey
->;
-export function getLoyaltyCustomerQueryOptions(
- id: GetLoyaltyCustomerPathParams["id"],
- options: GetLoyaltyCustomer["client"]["parameters"] = {},
-) {
- const queryKey = getLoyaltyCustomerQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetLoyaltyCustomer["data"],
- GetLoyaltyCustomer["error"]
- >({
- method: "get",
- url: `/loyalty-customer/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a loyalty customer
- * @summary Get loyalty customer
- * @link /loyalty-customer/:id
- */
-export function useGetLoyaltyCustomer<
- TData = GetLoyaltyCustomer["response"],
- TQueryData = GetLoyaltyCustomer["response"],
- TQueryKey extends QueryKey = GetLoyaltyCustomerQueryKey,
->(
- id: GetLoyaltyCustomerPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetLoyaltyCustomer["response"],
- GetLoyaltyCustomer["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetLoyaltyCustomer["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetLoyaltyCustomer["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getLoyaltyCustomerQueryKey(id);
- const query = useQuery({
- ...(getLoyaltyCustomerQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetLoyaltyCustomer["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getLoyaltyCustomerSuspenseQueryKey = (
- id: GetLoyaltyCustomerPathParams["id"],
-) => [{ url: "/loyalty-customer/:id", params: { id: id } }] as const;
-export type GetLoyaltyCustomerSuspenseQueryKey = ReturnType<
- typeof getLoyaltyCustomerSuspenseQueryKey
->;
-export function getLoyaltyCustomerSuspenseQueryOptions(
- id: GetLoyaltyCustomerPathParams["id"],
- options: GetLoyaltyCustomer["client"]["parameters"] = {},
-) {
- const queryKey = getLoyaltyCustomerSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetLoyaltyCustomer["data"],
- GetLoyaltyCustomer["error"]
- >({
- method: "get",
- url: `/loyalty-customer/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a loyalty customer
- * @summary Get loyalty customer
- * @link /loyalty-customer/:id
- */
-export function useGetLoyaltyCustomerSuspense<
- TData = GetLoyaltyCustomer["response"],
- TQueryKey extends QueryKey = GetLoyaltyCustomerSuspenseQueryKey,
->(
- id: GetLoyaltyCustomerPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetLoyaltyCustomer["response"],
- GetLoyaltyCustomer["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetLoyaltyCustomer["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetLoyaltyCustomer["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getLoyaltyCustomerSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getLoyaltyCustomerSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetLoyaltyCustomer["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetLoyaltyCustomerIdPoints.ts b/src/phoenix-generated/hooks/useGetLoyaltyCustomerIdPoints.ts
deleted file mode 100644
index 86e3f03d..00000000
--- a/src/phoenix-generated/hooks/useGetLoyaltyCustomerIdPoints.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetLoyaltyCustomerIdPoints400,
- GetLoyaltyCustomerIdPoints401,
- GetLoyaltyCustomerIdPoints404,
- GetLoyaltyCustomerIdPoints500,
- GetLoyaltyCustomerIdPointsPathParams,
- GetLoyaltyCustomerIdPointsQueryParams,
- GetLoyaltyCustomerIdPointsQueryResponse,
-} from "../types/GetLoyaltyCustomerIdPoints";
-
-type GetLoyaltyCustomerIdPointsClient = typeof client<
- GetLoyaltyCustomerIdPointsQueryResponse,
- | GetLoyaltyCustomerIdPoints400
- | GetLoyaltyCustomerIdPoints401
- | GetLoyaltyCustomerIdPoints404
- | GetLoyaltyCustomerIdPoints500,
- never
->;
-type GetLoyaltyCustomerIdPoints = {
- data: GetLoyaltyCustomerIdPointsQueryResponse;
- error:
- | GetLoyaltyCustomerIdPoints400
- | GetLoyaltyCustomerIdPoints401
- | GetLoyaltyCustomerIdPoints404
- | GetLoyaltyCustomerIdPoints500;
- request: never;
- pathParams: GetLoyaltyCustomerIdPointsPathParams;
- queryParams: GetLoyaltyCustomerIdPointsQueryParams;
- headerParams: never;
- response: GetLoyaltyCustomerIdPointsQueryResponse;
- client: {
- parameters: Partial<Parameters<GetLoyaltyCustomerIdPointsClient>[0]>;
- return: Awaited<ReturnType<GetLoyaltyCustomerIdPointsClient>>;
- };
-};
-export const getLoyaltyCustomerIdPointsQueryKey = (
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
-) =>
- [
- { url: "/loyalty-customer/:id/points", params: { id: id } },
- ...(params ? [params] : []),
- ] as const;
-export type GetLoyaltyCustomerIdPointsQueryKey = ReturnType<
- typeof getLoyaltyCustomerIdPointsQueryKey
->;
-export function getLoyaltyCustomerIdPointsQueryOptions(
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
- options: GetLoyaltyCustomerIdPoints["client"]["parameters"] = {},
-) {
- const queryKey = getLoyaltyCustomerIdPointsQueryKey(id, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetLoyaltyCustomerIdPoints["data"],
- GetLoyaltyCustomerIdPoints["error"]
- >({
- method: "get",
- url: `/loyalty-customer/${id}/points`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get the total points for a loyalty customer
- * @summary Get loyalty customer points
- * @link /loyalty-customer/:id/points
- */
-export function useGetLoyaltyCustomerIdPoints<
- TData = GetLoyaltyCustomerIdPoints["response"],
- TQueryData = GetLoyaltyCustomerIdPoints["response"],
- TQueryKey extends QueryKey = GetLoyaltyCustomerIdPointsQueryKey,
->(
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetLoyaltyCustomerIdPoints["response"],
- GetLoyaltyCustomerIdPoints["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetLoyaltyCustomerIdPoints["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetLoyaltyCustomerIdPoints["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getLoyaltyCustomerIdPointsQueryKey(id, params);
- const query = useQuery({
- ...(getLoyaltyCustomerIdPointsQueryOptions(
- id,
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetLoyaltyCustomerIdPoints["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getLoyaltyCustomerIdPointsSuspenseQueryKey = (
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
-) =>
- [
- { url: "/loyalty-customer/:id/points", params: { id: id } },
- ...(params ? [params] : []),
- ] as const;
-export type GetLoyaltyCustomerIdPointsSuspenseQueryKey = ReturnType<
- typeof getLoyaltyCustomerIdPointsSuspenseQueryKey
->;
-export function getLoyaltyCustomerIdPointsSuspenseQueryOptions(
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
- options: GetLoyaltyCustomerIdPoints["client"]["parameters"] = {},
-) {
- const queryKey = getLoyaltyCustomerIdPointsSuspenseQueryKey(id, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetLoyaltyCustomerIdPoints["data"],
- GetLoyaltyCustomerIdPoints["error"]
- >({
- method: "get",
- url: `/loyalty-customer/${id}/points`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get the total points for a loyalty customer
- * @summary Get loyalty customer points
- * @link /loyalty-customer/:id/points
- */
-export function useGetLoyaltyCustomerIdPointsSuspense<
- TData = GetLoyaltyCustomerIdPoints["response"],
- TQueryKey extends QueryKey = GetLoyaltyCustomerIdPointsSuspenseQueryKey,
->(
- id: GetLoyaltyCustomerIdPointsPathParams["id"],
- params?: GetLoyaltyCustomerIdPoints["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetLoyaltyCustomerIdPoints["response"],
- GetLoyaltyCustomerIdPoints["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetLoyaltyCustomerIdPoints["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetLoyaltyCustomerIdPoints["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getLoyaltyCustomerIdPointsSuspenseQueryKey(id, params);
- const query = useSuspenseQuery({
- ...(getLoyaltyCustomerIdPointsSuspenseQueryOptions(
- id,
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetLoyaltyCustomerIdPoints["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetOrderItemDecision.ts b/src/phoenix-generated/hooks/useGetOrderItemDecision.ts
deleted file mode 100644
index ab00e8f8..00000000
--- a/src/phoenix-generated/hooks/useGetOrderItemDecision.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetOrderItemDecision400,
- GetOrderItemDecision401,
- GetOrderItemDecision404,
- GetOrderItemDecision500,
- GetOrderItemDecisionPathParams,
- GetOrderItemDecisionQueryResponse,
-} from "../types/GetOrderItemDecision";
-
-type GetOrderItemDecisionClient = typeof client<
- GetOrderItemDecisionQueryResponse,
- | GetOrderItemDecision400
- | GetOrderItemDecision401
- | GetOrderItemDecision404
- | GetOrderItemDecision500,
- never
->;
-type GetOrderItemDecision = {
- data: GetOrderItemDecisionQueryResponse;
- error:
- | GetOrderItemDecision400
- | GetOrderItemDecision401
- | GetOrderItemDecision404
- | GetOrderItemDecision500;
- request: never;
- pathParams: GetOrderItemDecisionPathParams;
- queryParams: never;
- headerParams: never;
- response: GetOrderItemDecisionQueryResponse;
- client: {
- parameters: Partial<Parameters<GetOrderItemDecisionClient>[0]>;
- return: Awaited<ReturnType<GetOrderItemDecisionClient>>;
- };
-};
-export const getOrderItemDecisionQueryKey = (
- id: GetOrderItemDecisionPathParams["id"],
-) => [{ url: "/order-item-decisions/:id", params: { id: id } }] as const;
-export type GetOrderItemDecisionQueryKey = ReturnType<
- typeof getOrderItemDecisionQueryKey
->;
-export function getOrderItemDecisionQueryOptions(
- id: GetOrderItemDecisionPathParams["id"],
- options: GetOrderItemDecision["client"]["parameters"] = {},
-) {
- const queryKey = getOrderItemDecisionQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetOrderItemDecision["data"],
- GetOrderItemDecision["error"]
- >({
- method: "get",
- url: `/order-item-decisions/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get an order item decision by ID
- * @summary Get order item decision
- * @link /order-item-decisions/:id
- */
-export function useGetOrderItemDecision<
- TData = GetOrderItemDecision["response"],
- TQueryData = GetOrderItemDecision["response"],
- TQueryKey extends QueryKey = GetOrderItemDecisionQueryKey,
->(
- id: GetOrderItemDecisionPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetOrderItemDecision["response"],
- GetOrderItemDecision["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetOrderItemDecision["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetOrderItemDecision["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getOrderItemDecisionQueryKey(id);
- const query = useQuery({
- ...(getOrderItemDecisionQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetOrderItemDecision["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getOrderItemDecisionSuspenseQueryKey = (
- id: GetOrderItemDecisionPathParams["id"],
-) => [{ url: "/order-item-decisions/:id", params: { id: id } }] as const;
-export type GetOrderItemDecisionSuspenseQueryKey = ReturnType<
- typeof getOrderItemDecisionSuspenseQueryKey
->;
-export function getOrderItemDecisionSuspenseQueryOptions(
- id: GetOrderItemDecisionPathParams["id"],
- options: GetOrderItemDecision["client"]["parameters"] = {},
-) {
- const queryKey = getOrderItemDecisionSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetOrderItemDecision["data"],
- GetOrderItemDecision["error"]
- >({
- method: "get",
- url: `/order-item-decisions/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get an order item decision by ID
- * @summary Get order item decision
- * @link /order-item-decisions/:id
- */
-export function useGetOrderItemDecisionSuspense<
- TData = GetOrderItemDecision["response"],
- TQueryKey extends QueryKey = GetOrderItemDecisionSuspenseQueryKey,
->(
- id: GetOrderItemDecisionPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetOrderItemDecision["response"],
- GetOrderItemDecision["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetOrderItemDecision["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetOrderItemDecision["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getOrderItemDecisionSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getOrderItemDecisionSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetOrderItemDecision["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetOrderItemDecisionsTransactionItemTransactionItemId.ts b/src/phoenix-generated/hooks/useGetOrderItemDecisionsTransactionItemTransactionItemId.ts
deleted file mode 100644
index 92e119be..00000000
--- a/src/phoenix-generated/hooks/useGetOrderItemDecisionsTransactionItemTransactionItemId.ts
+++ /dev/null
@@ -1,227 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetOrderItemDecisionsTransactionItemTransactionItemId400,
- GetOrderItemDecisionsTransactionItemTransactionItemId401,
- GetOrderItemDecisionsTransactionItemTransactionItemId404,
- GetOrderItemDecisionsTransactionItemTransactionItemId500,
- GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams,
- GetOrderItemDecisionsTransactionItemTransactionItemIdQueryResponse,
-} from "../types/GetOrderItemDecisionsTransactionItemTransactionItemId";
-
-type GetOrderItemDecisionsTransactionItemTransactionItemIdClient =
- typeof client<
- GetOrderItemDecisionsTransactionItemTransactionItemIdQueryResponse,
- | GetOrderItemDecisionsTransactionItemTransactionItemId400
- | GetOrderItemDecisionsTransactionItemTransactionItemId401
- | GetOrderItemDecisionsTransactionItemTransactionItemId404
- | GetOrderItemDecisionsTransactionItemTransactionItemId500,
- never
- >;
-type GetOrderItemDecisionsTransactionItemTransactionItemId = {
- data: GetOrderItemDecisionsTransactionItemTransactionItemIdQueryResponse;
- error:
- | GetOrderItemDecisionsTransactionItemTransactionItemId400
- | GetOrderItemDecisionsTransactionItemTransactionItemId401
- | GetOrderItemDecisionsTransactionItemTransactionItemId404
- | GetOrderItemDecisionsTransactionItemTransactionItemId500;
- request: never;
- pathParams: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetOrderItemDecisionsTransactionItemTransactionItemIdQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetOrderItemDecisionsTransactionItemTransactionItemIdClient>[0]
- >;
- return: Awaited<
- ReturnType<GetOrderItemDecisionsTransactionItemTransactionItemIdClient>
- >;
- };
-};
-export const getOrderItemDecisionsTransactionItemTransactionItemIdQueryKey = (
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
-) =>
- [
- {
- url: "/order-item-decisions/transaction-item/:transaction_item_id",
- params: { transactionItemId: transactionItemId },
- },
- ] as const;
-export type GetOrderItemDecisionsTransactionItemTransactionItemIdQueryKey =
- ReturnType<
- typeof getOrderItemDecisionsTransactionItemTransactionItemIdQueryKey
- >;
-export function getOrderItemDecisionsTransactionItemTransactionItemIdQueryOptions(
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
- options: GetOrderItemDecisionsTransactionItemTransactionItemId["client"]["parameters"] = {},
-) {
- const queryKey =
- getOrderItemDecisionsTransactionItemTransactionItemIdQueryKey(
- transactionItemId,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetOrderItemDecisionsTransactionItemTransactionItemId["data"],
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
- >({
- method: "get",
- url: `/order-item-decisions/transaction-item/${transactionItemId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get all order item decisions for a specific transaction item
- * @summary Get order item decisions by transaction item
- * @link /order-item-decisions/transaction-item/:transaction_item_id
- */
-export function useGetOrderItemDecisionsTransactionItemTransactionItemId<
- TData = GetOrderItemDecisionsTransactionItemTransactionItemId["response"],
- TQueryData = GetOrderItemDecisionsTransactionItemTransactionItemId["response"],
- TQueryKey extends
- QueryKey = GetOrderItemDecisionsTransactionItemTransactionItemIdQueryKey,
->(
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetOrderItemDecisionsTransactionItemTransactionItemId["response"],
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetOrderItemDecisionsTransactionItemTransactionItemId["client"]["parameters"];
- } = {},
-): UseQueryResult<
- TData,
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getOrderItemDecisionsTransactionItemTransactionItemIdQueryKey(
- transactionItemId,
- );
- const query = useQuery({
- ...(getOrderItemDecisionsTransactionItemTransactionItemIdQueryOptions(
- transactionItemId,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey =
- (
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
- ) =>
- [
- {
- url: "/order-item-decisions/transaction-item/:transaction_item_id",
- params: { transactionItemId: transactionItemId },
- },
- ] as const;
-export type GetOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey =
- ReturnType<
- typeof getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey
- >;
-export function getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryOptions(
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
- options: GetOrderItemDecisionsTransactionItemTransactionItemId["client"]["parameters"] = {},
-) {
- const queryKey =
- getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey(
- transactionItemId,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetOrderItemDecisionsTransactionItemTransactionItemId["data"],
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
- >({
- method: "get",
- url: `/order-item-decisions/transaction-item/${transactionItemId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get all order item decisions for a specific transaction item
- * @summary Get order item decisions by transaction item
- * @link /order-item-decisions/transaction-item/:transaction_item_id
- */
-export function useGetOrderItemDecisionsTransactionItemTransactionItemIdSuspense<
- TData = GetOrderItemDecisionsTransactionItemTransactionItemId["response"],
- TQueryKey extends
- QueryKey = GetOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey,
->(
- transactionItemId: GetOrderItemDecisionsTransactionItemTransactionItemIdPathParams["transaction_item_id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetOrderItemDecisionsTransactionItemTransactionItemId["response"],
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetOrderItemDecisionsTransactionItemTransactionItemId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryKey(
- transactionItemId,
- );
- const query = useSuspenseQuery({
- ...(getOrderItemDecisionsTransactionItemTransactionItemIdSuspenseQueryOptions(
- transactionItemId,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetOrderItemDecisionsTransactionItemTransactionItemId["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetProducts.ts b/src/phoenix-generated/hooks/useGetProducts.ts
deleted file mode 100644
index 20cdd5ff..00000000
--- a/src/phoenix-generated/hooks/useGetProducts.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetProducts400,
- GetProducts401,
- GetProducts422,
- GetProducts500,
- GetProductsQueryParams,
- GetProductsQueryResponse,
-} from "../types/GetProducts";
-
-type GetProductsClient = typeof client<
- GetProductsQueryResponse,
- GetProducts400 | GetProducts401 | GetProducts422 | GetProducts500,
- never
->;
-type GetProducts = {
- data: GetProductsQueryResponse;
- error: GetProducts400 | GetProducts401 | GetProducts422 | GetProducts500;
- request: never;
- pathParams: never;
- queryParams: GetProductsQueryParams;
- headerParams: never;
- response: GetProductsQueryResponse;
- client: {
- parameters: Partial<Parameters<GetProductsClient>[0]>;
- return: Awaited<ReturnType<GetProductsClient>>;
- };
-};
-export const getProductsQueryKey = (params: GetProducts["queryParams"]) =>
- [{ url: "/products" }, ...(params ? [params] : [])] as const;
-export type GetProductsQueryKey = ReturnType<typeof getProductsQueryKey>;
-export function getProductsQueryOptions(
- params: GetProducts["queryParams"],
- options: GetProducts["client"]["parameters"] = {},
-) {
- const queryKey = getProductsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetProducts["data"], GetProducts["error"]>({
- method: "get",
- url: `/products`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List products for a storefront
- * @summary List products
- * @link /products
- */
-export function useGetProducts<
- TData = GetProducts["response"],
- TQueryData = GetProducts["response"],
- TQueryKey extends QueryKey = GetProductsQueryKey,
->(
- params: GetProducts["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetProducts["response"],
- GetProducts["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetProducts["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetProducts["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getProductsQueryKey(params);
- const query = useQuery({
- ...(getProductsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetProducts["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getProductsSuspenseQueryKey = (
- params: GetProducts["queryParams"],
-) => [{ url: "/products" }, ...(params ? [params] : [])] as const;
-export type GetProductsSuspenseQueryKey = ReturnType<
- typeof getProductsSuspenseQueryKey
->;
-export function getProductsSuspenseQueryOptions(
- params: GetProducts["queryParams"],
- options: GetProducts["client"]["parameters"] = {},
-) {
- const queryKey = getProductsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<GetProducts["data"], GetProducts["error"]>({
- method: "get",
- url: `/products`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List products for a storefront
- * @summary List products
- * @link /products
- */
-export function useGetProductsSuspense<
- TData = GetProducts["response"],
- TQueryKey extends QueryKey = GetProductsSuspenseQueryKey,
->(
- params: GetProducts["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetProducts["response"],
- GetProducts["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetProducts["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetProducts["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getProductsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(getProductsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetProducts["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetProductsProductId.ts b/src/phoenix-generated/hooks/useGetProductsProductId.ts
deleted file mode 100644
index dd0027fe..00000000
--- a/src/phoenix-generated/hooks/useGetProductsProductId.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetProductsProductId400,
- GetProductsProductId401,
- GetProductsProductId404,
- GetProductsProductId500,
- GetProductsProductIdPathParams,
- GetProductsProductIdQueryParams,
- GetProductsProductIdQueryResponse,
-} from "../types/GetProductsProductId";
-
-type GetProductsProductIdClient = typeof client<
- GetProductsProductIdQueryResponse,
- | GetProductsProductId400
- | GetProductsProductId401
- | GetProductsProductId404
- | GetProductsProductId500,
- never
->;
-type GetProductsProductId = {
- data: GetProductsProductIdQueryResponse;
- error:
- | GetProductsProductId400
- | GetProductsProductId401
- | GetProductsProductId404
- | GetProductsProductId500;
- request: never;
- pathParams: GetProductsProductIdPathParams;
- queryParams: GetProductsProductIdQueryParams;
- headerParams: never;
- response: GetProductsProductIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetProductsProductIdClient>[0]>;
- return: Awaited<ReturnType<GetProductsProductIdClient>>;
- };
-};
-export const getProductsProductIdQueryKey = (
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
-) =>
- [
- { url: "/products/:product_id", params: { productId: productId } },
- ...(params ? [params] : []),
- ] as const;
-export type GetProductsProductIdQueryKey = ReturnType<
- typeof getProductsProductIdQueryKey
->;
-export function getProductsProductIdQueryOptions(
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
- options: GetProductsProductId["client"]["parameters"] = {},
-) {
- const queryKey = getProductsProductIdQueryKey(productId, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetProductsProductId["data"],
- GetProductsProductId["error"]
- >({
- method: "get",
- url: `/products/${productId}`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get product by ID
- * @summary Get product
- * @link /products/:product_id
- */
-export function useGetProductsProductId<
- TData = GetProductsProductId["response"],
- TQueryData = GetProductsProductId["response"],
- TQueryKey extends QueryKey = GetProductsProductIdQueryKey,
->(
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetProductsProductId["response"],
- GetProductsProductId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetProductsProductId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetProductsProductId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getProductsProductIdQueryKey(productId, params);
- const query = useQuery({
- ...(getProductsProductIdQueryOptions(
- productId,
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetProductsProductId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getProductsProductIdSuspenseQueryKey = (
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
-) =>
- [
- { url: "/products/:product_id", params: { productId: productId } },
- ...(params ? [params] : []),
- ] as const;
-export type GetProductsProductIdSuspenseQueryKey = ReturnType<
- typeof getProductsProductIdSuspenseQueryKey
->;
-export function getProductsProductIdSuspenseQueryOptions(
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
- options: GetProductsProductId["client"]["parameters"] = {},
-) {
- const queryKey = getProductsProductIdSuspenseQueryKey(productId, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetProductsProductId["data"],
- GetProductsProductId["error"]
- >({
- method: "get",
- url: `/products/${productId}`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get product by ID
- * @summary Get product
- * @link /products/:product_id
- */
-export function useGetProductsProductIdSuspense<
- TData = GetProductsProductId["response"],
- TQueryKey extends QueryKey = GetProductsProductIdSuspenseQueryKey,
->(
- productId: GetProductsProductIdPathParams["product_id"],
- params: GetProductsProductId["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetProductsProductId["response"],
- GetProductsProductId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetProductsProductId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetProductsProductId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getProductsProductIdSuspenseQueryKey(productId, params);
- const query = useSuspenseQuery({
- ...(getProductsProductIdSuspenseQueryOptions(
- productId,
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetProductsProductId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetProductsStorefrontStorefrontIdPathPath.ts b/src/phoenix-generated/hooks/useGetProductsStorefrontStorefrontIdPathPath.ts
deleted file mode 100644
index bd045dc9..00000000
--- a/src/phoenix-generated/hooks/useGetProductsStorefrontStorefrontIdPathPath.ts
+++ /dev/null
@@ -1,246 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetProductsStorefrontStorefrontIdPathPath400,
- GetProductsStorefrontStorefrontIdPathPath401,
- GetProductsStorefrontStorefrontIdPathPath404,
- GetProductsStorefrontStorefrontIdPathPath500,
- GetProductsStorefrontStorefrontIdPathPathPathParams,
- GetProductsStorefrontStorefrontIdPathPathQueryParams,
- GetProductsStorefrontStorefrontIdPathPathQueryResponse,
-} from "../types/GetProductsStorefrontStorefrontIdPathPath";
-
-type GetProductsStorefrontStorefrontIdPathPathClient = typeof client<
- GetProductsStorefrontStorefrontIdPathPathQueryResponse,
- | GetProductsStorefrontStorefrontIdPathPath400
- | GetProductsStorefrontStorefrontIdPathPath401
- | GetProductsStorefrontStorefrontIdPathPath404
- | GetProductsStorefrontStorefrontIdPathPath500,
- never
->;
-type GetProductsStorefrontStorefrontIdPathPath = {
- data: GetProductsStorefrontStorefrontIdPathPathQueryResponse;
- error:
- | GetProductsStorefrontStorefrontIdPathPath400
- | GetProductsStorefrontStorefrontIdPathPath401
- | GetProductsStorefrontStorefrontIdPathPath404
- | GetProductsStorefrontStorefrontIdPathPath500;
- request: never;
- pathParams: GetProductsStorefrontStorefrontIdPathPathPathParams;
- queryParams: GetProductsStorefrontStorefrontIdPathPathQueryParams;
- headerParams: never;
- response: GetProductsStorefrontStorefrontIdPathPathQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetProductsStorefrontStorefrontIdPathPathClient>[0]
- >;
- return: Awaited<
- ReturnType<GetProductsStorefrontStorefrontIdPathPathClient>
- >;
- };
-};
-export const getProductsStorefrontStorefrontIdPathPathQueryKey = (
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
-) =>
- [
- {
- url: "/products/storefront/:storefront_id/path/:path",
- params: { storefrontId: storefrontId, path: path },
- },
- ...(params ? [params] : []),
- ] as const;
-export type GetProductsStorefrontStorefrontIdPathPathQueryKey = ReturnType<
- typeof getProductsStorefrontStorefrontIdPathPathQueryKey
->;
-export function getProductsStorefrontStorefrontIdPathPathQueryOptions(
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
- options: GetProductsStorefrontStorefrontIdPathPath["client"]["parameters"] = {},
-) {
- const queryKey = getProductsStorefrontStorefrontIdPathPathQueryKey(
- storefrontId,
- path,
- params,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetProductsStorefrontStorefrontIdPathPath["data"],
- GetProductsStorefrontStorefrontIdPathPath["error"]
- >({
- method: "get",
- url: `/products/storefront/${storefrontId}/path/${path}`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get product by storefront id and path
- * @summary Get product by storefront id and path
- * @link /products/storefront/:storefront_id/path/:path
- */
-export function useGetProductsStorefrontStorefrontIdPathPath<
- TData = GetProductsStorefrontStorefrontIdPathPath["response"],
- TQueryData = GetProductsStorefrontStorefrontIdPathPath["response"],
- TQueryKey extends
- QueryKey = GetProductsStorefrontStorefrontIdPathPathQueryKey,
->(
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetProductsStorefrontStorefrontIdPathPath["response"],
- GetProductsStorefrontStorefrontIdPathPath["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetProductsStorefrontStorefrontIdPathPath["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetProductsStorefrontStorefrontIdPathPath["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getProductsStorefrontStorefrontIdPathPathQueryKey(
- storefrontId,
- path,
- params,
- );
- const query = useQuery({
- ...(getProductsStorefrontStorefrontIdPathPathQueryOptions(
- storefrontId,
- path,
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetProductsStorefrontStorefrontIdPathPath["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getProductsStorefrontStorefrontIdPathPathSuspenseQueryKey = (
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
-) =>
- [
- {
- url: "/products/storefront/:storefront_id/path/:path",
- params: { storefrontId: storefrontId, path: path },
- },
- ...(params ? [params] : []),
- ] as const;
-export type GetProductsStorefrontStorefrontIdPathPathSuspenseQueryKey =
- ReturnType<typeof getProductsStorefrontStorefrontIdPathPathSuspenseQueryKey>;
-export function getProductsStorefrontStorefrontIdPathPathSuspenseQueryOptions(
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
- options: GetProductsStorefrontStorefrontIdPathPath["client"]["parameters"] = {},
-) {
- const queryKey = getProductsStorefrontStorefrontIdPathPathSuspenseQueryKey(
- storefrontId,
- path,
- params,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetProductsStorefrontStorefrontIdPathPath["data"],
- GetProductsStorefrontStorefrontIdPathPath["error"]
- >({
- method: "get",
- url: `/products/storefront/${storefrontId}/path/${path}`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get product by storefront id and path
- * @summary Get product by storefront id and path
- * @link /products/storefront/:storefront_id/path/:path
- */
-export function useGetProductsStorefrontStorefrontIdPathPathSuspense<
- TData = GetProductsStorefrontStorefrontIdPathPath["response"],
- TQueryKey extends
- QueryKey = GetProductsStorefrontStorefrontIdPathPathSuspenseQueryKey,
->(
- storefrontId: GetProductsStorefrontStorefrontIdPathPathPathParams["storefront_id"],
- path: GetProductsStorefrontStorefrontIdPathPathPathParams["path"],
- params: GetProductsStorefrontStorefrontIdPathPath["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetProductsStorefrontStorefrontIdPathPath["response"],
- GetProductsStorefrontStorefrontIdPathPath["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetProductsStorefrontStorefrontIdPathPath["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetProductsStorefrontStorefrontIdPathPath["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getProductsStorefrontStorefrontIdPathPathSuspenseQueryKey(
- storefrontId,
- path,
- params,
- );
- const query = useSuspenseQuery({
- ...(getProductsStorefrontStorefrontIdPathPathSuspenseQueryOptions(
- storefrontId,
- path,
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetProductsStorefrontStorefrontIdPathPath["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStoreHoursEntitySalesChannelEntitySalesChannelId.ts b/src/phoenix-generated/hooks/useGetStoreHoursEntitySalesChannelEntitySalesChannelId.ts
deleted file mode 100644
index a13099e3..00000000
--- a/src/phoenix-generated/hooks/useGetStoreHoursEntitySalesChannelEntitySalesChannelId.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStoreHoursEntitySalesChannelEntitySalesChannelId400,
- GetStoreHoursEntitySalesChannelEntitySalesChannelId500,
- GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams,
- GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryResponse,
-} from "../types/GetStoreHoursEntitySalesChannelEntitySalesChannelId";
-
-type GetStoreHoursEntitySalesChannelEntitySalesChannelIdClient = typeof client<
- GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryResponse,
- | GetStoreHoursEntitySalesChannelEntitySalesChannelId400
- | GetStoreHoursEntitySalesChannelEntitySalesChannelId500,
- never
->;
-type GetStoreHoursEntitySalesChannelEntitySalesChannelId = {
- data: GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryResponse;
- error:
- | GetStoreHoursEntitySalesChannelEntitySalesChannelId400
- | GetStoreHoursEntitySalesChannelEntitySalesChannelId500;
- request: never;
- pathParams: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetStoreHoursEntitySalesChannelEntitySalesChannelIdClient>[0]
- >;
- return: Awaited<
- ReturnType<GetStoreHoursEntitySalesChannelEntitySalesChannelIdClient>
- >;
- };
-};
-export const getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey = (
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
-) =>
- [
- {
- url: "/store-hours/entity-sales-channel/:entity_sales_channel_id",
- params: { entitySalesChannelId: entitySalesChannelId },
- },
- ] as const;
-export type GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey =
- ReturnType<
- typeof getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey
- >;
-export function getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryOptions(
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
- options: GetStoreHoursEntitySalesChannelEntitySalesChannelId["client"]["parameters"] = {},
-) {
- const queryKey =
- getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey(
- entitySalesChannelId,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["data"],
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
- >({
- method: "get",
- url: `/store-hours/entity-sales-channel/${entitySalesChannelId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get store hours for a specific entity sales channel
- * @summary Get store hours by entity sales channel
- * @link /store-hours/entity-sales-channel/:entity_sales_channel_id
- */
-export function useGetStoreHoursEntitySalesChannelEntitySalesChannelId<
- TData = GetStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- TQueryData = GetStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- TQueryKey extends
- QueryKey = GetStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey,
->(
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStoreHoursEntitySalesChannelEntitySalesChannelId["client"]["parameters"];
- } = {},
-): UseQueryResult<
- TData,
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryKey(
- entitySalesChannelId,
- );
- const query = useQuery({
- ...(getStoreHoursEntitySalesChannelEntitySalesChannelIdQueryOptions(
- entitySalesChannelId,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey =
- (
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
- ) =>
- [
- {
- url: "/store-hours/entity-sales-channel/:entity_sales_channel_id",
- params: { entitySalesChannelId: entitySalesChannelId },
- },
- ] as const;
-export type GetStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey =
- ReturnType<
- typeof getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey
- >;
-export function getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryOptions(
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
- options: GetStoreHoursEntitySalesChannelEntitySalesChannelId["client"]["parameters"] = {},
-) {
- const queryKey =
- getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey(
- entitySalesChannelId,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["data"],
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
- >({
- method: "get",
- url: `/store-hours/entity-sales-channel/${entitySalesChannelId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get store hours for a specific entity sales channel
- * @summary Get store hours by entity sales channel
- * @link /store-hours/entity-sales-channel/:entity_sales_channel_id
- */
-export function useGetStoreHoursEntitySalesChannelEntitySalesChannelIdSuspense<
- TData = GetStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- TQueryKey extends
- QueryKey = GetStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey,
->(
- entitySalesChannelId: GetStoreHoursEntitySalesChannelEntitySalesChannelIdPathParams["entity_sales_channel_id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["response"],
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStoreHoursEntitySalesChannelEntitySalesChannelId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryKey(
- entitySalesChannelId,
- );
- const query = useSuspenseQuery({
- ...(getStoreHoursEntitySalesChannelEntitySalesChannelIdSuspenseQueryOptions(
- entitySalesChannelId,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetStoreHoursEntitySalesChannelEntitySalesChannelId["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontPagesPageid.ts b/src/phoenix-generated/hooks/useGetStorefrontPagesPageid.ts
deleted file mode 100644
index b276dc04..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontPagesPageid.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontPagesPageid400,
- GetStorefrontPagesPageid401,
- GetStorefrontPagesPageid404,
- GetStorefrontPagesPageid500,
- GetStorefrontPagesPageidPathParams,
- GetStorefrontPagesPageidQueryResponse,
-} from "../types/GetStorefrontPagesPageid";
-
-type GetStorefrontPagesPageidClient = typeof client<
- GetStorefrontPagesPageidQueryResponse,
- | GetStorefrontPagesPageid400
- | GetStorefrontPagesPageid401
- | GetStorefrontPagesPageid404
- | GetStorefrontPagesPageid500,
- never
->;
-type GetStorefrontPagesPageid = {
- data: GetStorefrontPagesPageidQueryResponse;
- error:
- | GetStorefrontPagesPageid400
- | GetStorefrontPagesPageid401
- | GetStorefrontPagesPageid404
- | GetStorefrontPagesPageid500;
- request: never;
- pathParams: GetStorefrontPagesPageidPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontPagesPageidQueryResponse;
- client: {
- parameters: Partial<Parameters<GetStorefrontPagesPageidClient>[0]>;
- return: Awaited<ReturnType<GetStorefrontPagesPageidClient>>;
- };
-};
-export const getStorefrontPagesPageidQueryKey = (
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
-) =>
- [{ url: "/storefront-pages/:pageId", params: { pageId: pageId } }] as const;
-export type GetStorefrontPagesPageidQueryKey = ReturnType<
- typeof getStorefrontPagesPageidQueryKey
->;
-export function getStorefrontPagesPageidQueryOptions(
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
- options: GetStorefrontPagesPageid["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontPagesPageidQueryKey(pageId);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontPagesPageid["data"],
- GetStorefrontPagesPageid["error"]
- >({
- method: "get",
- url: `/storefront-pages/${pageId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a specific storefront page by its ID
- * @summary Get storefront page by ID
- * @link /storefront-pages/:pageId
- */
-export function useGetStorefrontPagesPageid<
- TData = GetStorefrontPagesPageid["response"],
- TQueryData = GetStorefrontPagesPageid["response"],
- TQueryKey extends QueryKey = GetStorefrontPagesPageidQueryKey,
->(
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontPagesPageid["response"],
- GetStorefrontPagesPageid["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontPagesPageid["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontPagesPageid["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getStorefrontPagesPageidQueryKey(pageId);
- const query = useQuery({
- ...(getStorefrontPagesPageidQueryOptions(
- pageId,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetStorefrontPagesPageid["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontPagesPageidSuspenseQueryKey = (
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
-) =>
- [{ url: "/storefront-pages/:pageId", params: { pageId: pageId } }] as const;
-export type GetStorefrontPagesPageidSuspenseQueryKey = ReturnType<
- typeof getStorefrontPagesPageidSuspenseQueryKey
->;
-export function getStorefrontPagesPageidSuspenseQueryOptions(
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
- options: GetStorefrontPagesPageid["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontPagesPageidSuspenseQueryKey(pageId);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontPagesPageid["data"],
- GetStorefrontPagesPageid["error"]
- >({
- method: "get",
- url: `/storefront-pages/${pageId}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a specific storefront page by its ID
- * @summary Get storefront page by ID
- * @link /storefront-pages/:pageId
- */
-export function useGetStorefrontPagesPageidSuspense<
- TData = GetStorefrontPagesPageid["response"],
- TQueryKey extends QueryKey = GetStorefrontPagesPageidSuspenseQueryKey,
->(
- pageId: GetStorefrontPagesPageidPathParams["pageId"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontPagesPageid["response"],
- GetStorefrontPagesPageid["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontPagesPageid["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetStorefrontPagesPageid["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getStorefrontPagesPageidSuspenseQueryKey(pageId);
- const query = useSuspenseQuery({
- ...(getStorefrontPagesPageidSuspenseQueryOptions(
- pageId,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetStorefrontPagesPageid["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsCustomDomainCustomDomain.ts b/src/phoenix-generated/hooks/useGetStorefrontsCustomDomainCustomDomain.ts
deleted file mode 100644
index 483cea1c..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsCustomDomainCustomDomain.ts
+++ /dev/null
@@ -1,205 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsCustomDomainCustomDomain401,
- GetStorefrontsCustomDomainCustomDomain404,
- GetStorefrontsCustomDomainCustomDomain500,
- GetStorefrontsCustomDomainCustomDomainPathParams,
- GetStorefrontsCustomDomainCustomDomainQueryResponse,
-} from "../types/GetStorefrontsCustomDomainCustomDomain";
-
-type GetStorefrontsCustomDomainCustomDomainClient = typeof client<
- GetStorefrontsCustomDomainCustomDomainQueryResponse,
- | GetStorefrontsCustomDomainCustomDomain401
- | GetStorefrontsCustomDomainCustomDomain404
- | GetStorefrontsCustomDomainCustomDomain500,
- never
->;
-type GetStorefrontsCustomDomainCustomDomain = {
- data: GetStorefrontsCustomDomainCustomDomainQueryResponse;
- error:
- | GetStorefrontsCustomDomainCustomDomain401
- | GetStorefrontsCustomDomainCustomDomain404
- | GetStorefrontsCustomDomainCustomDomain500;
- request: never;
- pathParams: GetStorefrontsCustomDomainCustomDomainPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontsCustomDomainCustomDomainQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetStorefrontsCustomDomainCustomDomainClient>[0]
- >;
- return: Awaited<ReturnType<GetStorefrontsCustomDomainCustomDomainClient>>;
- };
-};
-export const getStorefrontsCustomDomainCustomDomainQueryKey = (
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
-) =>
- [
- {
- url: "/storefronts/custom-domain/:custom_domain",
- params: { customDomain: customDomain },
- },
- ] as const;
-export type GetStorefrontsCustomDomainCustomDomainQueryKey = ReturnType<
- typeof getStorefrontsCustomDomainCustomDomainQueryKey
->;
-export function getStorefrontsCustomDomainCustomDomainQueryOptions(
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
- options: GetStorefrontsCustomDomainCustomDomain["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsCustomDomainCustomDomainQueryKey(customDomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsCustomDomainCustomDomain["data"],
- GetStorefrontsCustomDomainCustomDomain["error"]
- >({
- method: "get",
- url: `/storefronts/custom-domain/${customDomain}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its custom domain
- * @summary Get storefront by custom domain
- * @link /storefronts/custom-domain/:custom_domain
- */
-export function useGetStorefrontsCustomDomainCustomDomain<
- TData = GetStorefrontsCustomDomainCustomDomain["response"],
- TQueryData = GetStorefrontsCustomDomainCustomDomain["response"],
- TQueryKey extends QueryKey = GetStorefrontsCustomDomainCustomDomainQueryKey,
->(
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsCustomDomainCustomDomain["response"],
- GetStorefrontsCustomDomainCustomDomain["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsCustomDomainCustomDomain["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsCustomDomainCustomDomain["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsCustomDomainCustomDomainQueryKey(customDomain);
- const query = useQuery({
- ...(getStorefrontsCustomDomainCustomDomainQueryOptions(
- customDomain,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetStorefrontsCustomDomainCustomDomain["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsCustomDomainCustomDomainSuspenseQueryKey = (
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
-) =>
- [
- {
- url: "/storefronts/custom-domain/:custom_domain",
- params: { customDomain: customDomain },
- },
- ] as const;
-export type GetStorefrontsCustomDomainCustomDomainSuspenseQueryKey = ReturnType<
- typeof getStorefrontsCustomDomainCustomDomainSuspenseQueryKey
->;
-export function getStorefrontsCustomDomainCustomDomainSuspenseQueryOptions(
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
- options: GetStorefrontsCustomDomainCustomDomain["client"]["parameters"] = {},
-) {
- const queryKey =
- getStorefrontsCustomDomainCustomDomainSuspenseQueryKey(customDomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsCustomDomainCustomDomain["data"],
- GetStorefrontsCustomDomainCustomDomain["error"]
- >({
- method: "get",
- url: `/storefronts/custom-domain/${customDomain}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its custom domain
- * @summary Get storefront by custom domain
- * @link /storefronts/custom-domain/:custom_domain
- */
-export function useGetStorefrontsCustomDomainCustomDomainSuspense<
- TData = GetStorefrontsCustomDomainCustomDomain["response"],
- TQueryKey extends
- QueryKey = GetStorefrontsCustomDomainCustomDomainSuspenseQueryKey,
->(
- customDomain: GetStorefrontsCustomDomainCustomDomainPathParams["custom_domain"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsCustomDomainCustomDomain["response"],
- GetStorefrontsCustomDomainCustomDomain["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsCustomDomainCustomDomain["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetStorefrontsCustomDomainCustomDomain["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsCustomDomainCustomDomainSuspenseQueryKey(customDomain);
- const query = useSuspenseQuery({
- ...(getStorefrontsCustomDomainCustomDomainSuspenseQueryOptions(
- customDomain,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetStorefrontsCustomDomainCustomDomain["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsId.ts b/src/phoenix-generated/hooks/useGetStorefrontsId.ts
deleted file mode 100644
index 1e2dd0db..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsId.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsId401,
- GetStorefrontsId404,
- GetStorefrontsId500,
- GetStorefrontsIdPathParams,
- GetStorefrontsIdQueryResponse,
-} from "../types/GetStorefrontsId";
-
-type GetStorefrontsIdClient = typeof client<
- GetStorefrontsIdQueryResponse,
- GetStorefrontsId401 | GetStorefrontsId404 | GetStorefrontsId500,
- never
->;
-type GetStorefrontsId = {
- data: GetStorefrontsIdQueryResponse;
- error: GetStorefrontsId401 | GetStorefrontsId404 | GetStorefrontsId500;
- request: never;
- pathParams: GetStorefrontsIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontsIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetStorefrontsIdClient>[0]>;
- return: Awaited<ReturnType<GetStorefrontsIdClient>>;
- };
-};
-export const getStorefrontsIdQueryKey = (
- id: GetStorefrontsIdPathParams["id"],
-) => [{ url: "/storefronts/:id", params: { id: id } }] as const;
-export type GetStorefrontsIdQueryKey = ReturnType<
- typeof getStorefrontsIdQueryKey
->;
-export function getStorefrontsIdQueryOptions(
- id: GetStorefrontsIdPathParams["id"],
- options: GetStorefrontsId["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsIdQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsId["data"],
- GetStorefrontsId["error"]
- >({
- method: "get",
- url: `/storefronts/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its ID
- * @summary Get storefront by ID
- * @link /storefronts/:id
- */
-export function useGetStorefrontsId<
- TData = GetStorefrontsId["response"],
- TQueryData = GetStorefrontsId["response"],
- TQueryKey extends QueryKey = GetStorefrontsIdQueryKey,
->(
- id: GetStorefrontsIdPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsId["response"],
- GetStorefrontsId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getStorefrontsIdQueryKey(id);
- const query = useQuery({
- ...(getStorefrontsIdQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetStorefrontsId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsIdSuspenseQueryKey = (
- id: GetStorefrontsIdPathParams["id"],
-) => [{ url: "/storefronts/:id", params: { id: id } }] as const;
-export type GetStorefrontsIdSuspenseQueryKey = ReturnType<
- typeof getStorefrontsIdSuspenseQueryKey
->;
-export function getStorefrontsIdSuspenseQueryOptions(
- id: GetStorefrontsIdPathParams["id"],
- options: GetStorefrontsId["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsIdSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsId["data"],
- GetStorefrontsId["error"]
- >({
- method: "get",
- url: `/storefronts/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its ID
- * @summary Get storefront by ID
- * @link /storefronts/:id
- */
-export function useGetStorefrontsIdSuspense<
- TData = GetStorefrontsId["response"],
- TQueryKey extends QueryKey = GetStorefrontsIdSuspenseQueryKey,
->(
- id: GetStorefrontsIdPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsId["response"],
- GetStorefrontsId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetStorefrontsId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getStorefrontsIdSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getStorefrontsIdSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetStorefrontsId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsIdPages.ts b/src/phoenix-generated/hooks/useGetStorefrontsIdPages.ts
deleted file mode 100644
index 0d07f630..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsIdPages.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsIdPages400,
- GetStorefrontsIdPages401,
- GetStorefrontsIdPages404,
- GetStorefrontsIdPages500,
- GetStorefrontsIdPagesPathParams,
- GetStorefrontsIdPagesQueryParams,
- GetStorefrontsIdPagesQueryResponse,
-} from "../types/GetStorefrontsIdPages";
-
-type GetStorefrontsIdPagesClient = typeof client<
- GetStorefrontsIdPagesQueryResponse,
- | GetStorefrontsIdPages400
- | GetStorefrontsIdPages401
- | GetStorefrontsIdPages404
- | GetStorefrontsIdPages500,
- never
->;
-type GetStorefrontsIdPages = {
- data: GetStorefrontsIdPagesQueryResponse;
- error:
- | GetStorefrontsIdPages400
- | GetStorefrontsIdPages401
- | GetStorefrontsIdPages404
- | GetStorefrontsIdPages500;
- request: never;
- pathParams: GetStorefrontsIdPagesPathParams;
- queryParams: GetStorefrontsIdPagesQueryParams;
- headerParams: never;
- response: GetStorefrontsIdPagesQueryResponse;
- client: {
- parameters: Partial<Parameters<GetStorefrontsIdPagesClient>[0]>;
- return: Awaited<ReturnType<GetStorefrontsIdPagesClient>>;
- };
-};
-export const getStorefrontsIdPagesQueryKey = (
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
-) =>
- [
- { url: "/storefronts/:id/pages", params: { id: id } },
- ...(params ? [params] : []),
- ] as const;
-export type GetStorefrontsIdPagesQueryKey = ReturnType<
- typeof getStorefrontsIdPagesQueryKey
->;
-export function getStorefrontsIdPagesQueryOptions(
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
- options: GetStorefrontsIdPages["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsIdPagesQueryKey(id, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsIdPages["data"],
- GetStorefrontsIdPages["error"]
- >({
- method: "get",
- url: `/storefronts/${id}/pages`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List pages for a specific storefront
- * @summary List storefront pages
- * @link /storefronts/:id/pages
- */
-export function useGetStorefrontsIdPages<
- TData = GetStorefrontsIdPages["response"],
- TQueryData = GetStorefrontsIdPages["response"],
- TQueryKey extends QueryKey = GetStorefrontsIdPagesQueryKey,
->(
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsIdPages["response"],
- GetStorefrontsIdPages["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsIdPages["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsIdPages["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getStorefrontsIdPagesQueryKey(id, params);
- const query = useQuery({
- ...(getStorefrontsIdPagesQueryOptions(
- id,
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetStorefrontsIdPages["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsIdPagesSuspenseQueryKey = (
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
-) =>
- [
- { url: "/storefronts/:id/pages", params: { id: id } },
- ...(params ? [params] : []),
- ] as const;
-export type GetStorefrontsIdPagesSuspenseQueryKey = ReturnType<
- typeof getStorefrontsIdPagesSuspenseQueryKey
->;
-export function getStorefrontsIdPagesSuspenseQueryOptions(
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
- options: GetStorefrontsIdPages["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsIdPagesSuspenseQueryKey(id, params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsIdPages["data"],
- GetStorefrontsIdPages["error"]
- >({
- method: "get",
- url: `/storefronts/${id}/pages`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List pages for a specific storefront
- * @summary List storefront pages
- * @link /storefronts/:id/pages
- */
-export function useGetStorefrontsIdPagesSuspense<
- TData = GetStorefrontsIdPages["response"],
- TQueryKey extends QueryKey = GetStorefrontsIdPagesSuspenseQueryKey,
->(
- id: GetStorefrontsIdPagesPathParams["id"],
- params?: GetStorefrontsIdPages["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsIdPages["response"],
- GetStorefrontsIdPages["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsIdPages["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetStorefrontsIdPages["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getStorefrontsIdPagesSuspenseQueryKey(id, params);
- const query = useSuspenseQuery({
- ...(getStorefrontsIdPagesSuspenseQueryOptions(
- id,
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetStorefrontsIdPages["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomain.ts b/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomain.ts
deleted file mode 100644
index 7343d1c3..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomain.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsSubdomainSubdomain401,
- GetStorefrontsSubdomainSubdomain404,
- GetStorefrontsSubdomainSubdomain500,
- GetStorefrontsSubdomainSubdomainPathParams,
- GetStorefrontsSubdomainSubdomainQueryResponse,
-} from "../types/GetStorefrontsSubdomainSubdomain";
-
-type GetStorefrontsSubdomainSubdomainClient = typeof client<
- GetStorefrontsSubdomainSubdomainQueryResponse,
- | GetStorefrontsSubdomainSubdomain401
- | GetStorefrontsSubdomainSubdomain404
- | GetStorefrontsSubdomainSubdomain500,
- never
->;
-type GetStorefrontsSubdomainSubdomain = {
- data: GetStorefrontsSubdomainSubdomainQueryResponse;
- error:
- | GetStorefrontsSubdomainSubdomain401
- | GetStorefrontsSubdomainSubdomain404
- | GetStorefrontsSubdomainSubdomain500;
- request: never;
- pathParams: GetStorefrontsSubdomainSubdomainPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontsSubdomainSubdomainQueryResponse;
- client: {
- parameters: Partial<Parameters<GetStorefrontsSubdomainSubdomainClient>[0]>;
- return: Awaited<ReturnType<GetStorefrontsSubdomainSubdomainClient>>;
- };
-};
-export const getStorefrontsSubdomainSubdomainQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain",
- params: { subdomain: subdomain },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainQueryKey = ReturnType<
- typeof getStorefrontsSubdomainSubdomainQueryKey
->;
-export function getStorefrontsSubdomainSubdomainQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
- options: GetStorefrontsSubdomainSubdomain["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsSubdomainSubdomainQueryKey(subdomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomain["data"],
- GetStorefrontsSubdomainSubdomain["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its subdomain
- * @summary Get storefront by subdomain
- * @link /storefronts/subdomain/:subdomain
- */
-export function useGetStorefrontsSubdomainSubdomain<
- TData = GetStorefrontsSubdomainSubdomain["response"],
- TQueryData = GetStorefrontsSubdomainSubdomain["response"],
- TQueryKey extends QueryKey = GetStorefrontsSubdomainSubdomainQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsSubdomainSubdomain["response"],
- GetStorefrontsSubdomainSubdomain["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomain["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsSubdomainSubdomain["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainQueryKey(subdomain);
- const query = useQuery({
- ...(getStorefrontsSubdomainSubdomainQueryOptions(
- subdomain,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetStorefrontsSubdomainSubdomain["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsSubdomainSubdomainSuspenseQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain",
- params: { subdomain: subdomain },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainSuspenseQueryKey = ReturnType<
- typeof getStorefrontsSubdomainSubdomainSuspenseQueryKey
->;
-export function getStorefrontsSubdomainSubdomainSuspenseQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
- options: GetStorefrontsSubdomainSubdomain["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsSubdomainSubdomainSuspenseQueryKey(subdomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomain["data"],
- GetStorefrontsSubdomainSubdomain["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a storefront by its subdomain
- * @summary Get storefront by subdomain
- * @link /storefronts/subdomain/:subdomain
- */
-export function useGetStorefrontsSubdomainSubdomainSuspense<
- TData = GetStorefrontsSubdomainSubdomain["response"],
- TQueryKey extends QueryKey = GetStorefrontsSubdomainSubdomainSuspenseQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainPathParams["subdomain"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsSubdomainSubdomain["response"],
- GetStorefrontsSubdomainSubdomain["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomain["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetStorefrontsSubdomainSubdomain["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainSuspenseQueryKey(subdomain);
- const query = useSuspenseQuery({
- ...(getStorefrontsSubdomainSubdomainSuspenseQueryOptions(
- subdomain,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomain["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainCheck.ts b/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainCheck.ts
deleted file mode 100644
index 3d27ebbe..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainCheck.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsSubdomainSubdomainCheck400,
- GetStorefrontsSubdomainSubdomainCheck500,
- GetStorefrontsSubdomainSubdomainCheckPathParams,
- GetStorefrontsSubdomainSubdomainCheckQueryResponse,
-} from "../types/GetStorefrontsSubdomainSubdomainCheck";
-
-type GetStorefrontsSubdomainSubdomainCheckClient = typeof client<
- GetStorefrontsSubdomainSubdomainCheckQueryResponse,
- | GetStorefrontsSubdomainSubdomainCheck400
- | GetStorefrontsSubdomainSubdomainCheck500,
- never
->;
-type GetStorefrontsSubdomainSubdomainCheck = {
- data: GetStorefrontsSubdomainSubdomainCheckQueryResponse;
- error:
- | GetStorefrontsSubdomainSubdomainCheck400
- | GetStorefrontsSubdomainSubdomainCheck500;
- request: never;
- pathParams: GetStorefrontsSubdomainSubdomainCheckPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontsSubdomainSubdomainCheckQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetStorefrontsSubdomainSubdomainCheckClient>[0]
- >;
- return: Awaited<ReturnType<GetStorefrontsSubdomainSubdomainCheckClient>>;
- };
-};
-export const getStorefrontsSubdomainSubdomainCheckQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain/check",
- params: { subdomain: subdomain },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainCheckQueryKey = ReturnType<
- typeof getStorefrontsSubdomainSubdomainCheckQueryKey
->;
-export function getStorefrontsSubdomainSubdomainCheckQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
- options: GetStorefrontsSubdomainSubdomainCheck["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsSubdomainSubdomainCheckQueryKey(subdomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomainCheck["data"],
- GetStorefrontsSubdomainSubdomainCheck["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}/check`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Check if a subdomain is available for use
- * @summary Check subdomain availability
- * @link /storefronts/subdomain/:subdomain/check
- */
-export function useGetStorefrontsSubdomainSubdomainCheck<
- TData = GetStorefrontsSubdomainSubdomainCheck["response"],
- TQueryData = GetStorefrontsSubdomainSubdomainCheck["response"],
- TQueryKey extends QueryKey = GetStorefrontsSubdomainSubdomainCheckQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsSubdomainSubdomainCheck["response"],
- GetStorefrontsSubdomainSubdomainCheck["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomainCheck["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsSubdomainSubdomainCheck["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainCheckQueryKey(subdomain);
- const query = useQuery({
- ...(getStorefrontsSubdomainSubdomainCheckQueryOptions(
- subdomain,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainCheck["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsSubdomainSubdomainCheckSuspenseQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain/check",
- params: { subdomain: subdomain },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainCheckSuspenseQueryKey = ReturnType<
- typeof getStorefrontsSubdomainSubdomainCheckSuspenseQueryKey
->;
-export function getStorefrontsSubdomainSubdomainCheckSuspenseQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
- options: GetStorefrontsSubdomainSubdomainCheck["client"]["parameters"] = {},
-) {
- const queryKey =
- getStorefrontsSubdomainSubdomainCheckSuspenseQueryKey(subdomain);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomainCheck["data"],
- GetStorefrontsSubdomainSubdomainCheck["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}/check`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Check if a subdomain is available for use
- * @summary Check subdomain availability
- * @link /storefronts/subdomain/:subdomain/check
- */
-export function useGetStorefrontsSubdomainSubdomainCheckSuspense<
- TData = GetStorefrontsSubdomainSubdomainCheck["response"],
- TQueryKey extends
- QueryKey = GetStorefrontsSubdomainSubdomainCheckSuspenseQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainCheckPathParams["subdomain"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsSubdomainSubdomainCheck["response"],
- GetStorefrontsSubdomainSubdomainCheck["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomainCheck["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainCheck["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainCheckSuspenseQueryKey(subdomain);
- const query = useSuspenseQuery({
- ...(getStorefrontsSubdomainSubdomainCheckSuspenseQueryOptions(
- subdomain,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainCheck["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainPagesPath.ts b/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainPagesPath.ts
deleted file mode 100644
index 17bcf881..00000000
--- a/src/phoenix-generated/hooks/useGetStorefrontsSubdomainSubdomainPagesPath.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetStorefrontsSubdomainSubdomainPagesPath400,
- GetStorefrontsSubdomainSubdomainPagesPath404,
- GetStorefrontsSubdomainSubdomainPagesPath500,
- GetStorefrontsSubdomainSubdomainPagesPathPathParams,
- GetStorefrontsSubdomainSubdomainPagesPathQueryResponse,
-} from "../types/GetStorefrontsSubdomainSubdomainPagesPath";
-
-type GetStorefrontsSubdomainSubdomainPagesPathClient = typeof client<
- GetStorefrontsSubdomainSubdomainPagesPathQueryResponse,
- | GetStorefrontsSubdomainSubdomainPagesPath400
- | GetStorefrontsSubdomainSubdomainPagesPath404
- | GetStorefrontsSubdomainSubdomainPagesPath500,
- never
->;
-type GetStorefrontsSubdomainSubdomainPagesPath = {
- data: GetStorefrontsSubdomainSubdomainPagesPathQueryResponse;
- error:
- | GetStorefrontsSubdomainSubdomainPagesPath400
- | GetStorefrontsSubdomainSubdomainPagesPath404
- | GetStorefrontsSubdomainSubdomainPagesPath500;
- request: never;
- pathParams: GetStorefrontsSubdomainSubdomainPagesPathPathParams;
- queryParams: never;
- headerParams: never;
- response: GetStorefrontsSubdomainSubdomainPagesPathQueryResponse;
- client: {
- parameters: Partial<
- Parameters<GetStorefrontsSubdomainSubdomainPagesPathClient>[0]
- >;
- return: Awaited<
- ReturnType<GetStorefrontsSubdomainSubdomainPagesPathClient>
- >;
- };
-};
-export const getStorefrontsSubdomainSubdomainPagesPathQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain/pages/:path",
- params: { subdomain: subdomain, path: path },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainPagesPathQueryKey = ReturnType<
- typeof getStorefrontsSubdomainSubdomainPagesPathQueryKey
->;
-export function getStorefrontsSubdomainSubdomainPagesPathQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
- options: GetStorefrontsSubdomainSubdomainPagesPath["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsSubdomainSubdomainPagesPathQueryKey(
- subdomain,
- path,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomainPagesPath["data"],
- GetStorefrontsSubdomainSubdomainPagesPath["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}/pages/${path}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a specific page by storefront subdomain and page path
- * @summary Get storefront page by subdomain and path
- * @link /storefronts/subdomain/:subdomain/pages/:path
- */
-export function useGetStorefrontsSubdomainSubdomainPagesPath<
- TData = GetStorefrontsSubdomainSubdomainPagesPath["response"],
- TQueryData = GetStorefrontsSubdomainSubdomainPagesPath["response"],
- TQueryKey extends
- QueryKey = GetStorefrontsSubdomainSubdomainPagesPathQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetStorefrontsSubdomainSubdomainPagesPath["response"],
- GetStorefrontsSubdomainSubdomainPagesPath["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomainPagesPath["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetStorefrontsSubdomainSubdomainPagesPath["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainPagesPathQueryKey(subdomain, path);
- const query = useQuery({
- ...(getStorefrontsSubdomainSubdomainPagesPathQueryOptions(
- subdomain,
- path,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainPagesPath["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey = (
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
-) =>
- [
- {
- url: "/storefronts/subdomain/:subdomain/pages/:path",
- params: { subdomain: subdomain, path: path },
- },
- ] as const;
-export type GetStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey =
- ReturnType<typeof getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey>;
-export function getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryOptions(
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
- options: GetStorefrontsSubdomainSubdomainPagesPath["client"]["parameters"] = {},
-) {
- const queryKey = getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey(
- subdomain,
- path,
- );
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetStorefrontsSubdomainSubdomainPagesPath["data"],
- GetStorefrontsSubdomainSubdomainPagesPath["error"]
- >({
- method: "get",
- url: `/storefronts/subdomain/${subdomain}/pages/${path}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get a specific page by storefront subdomain and page path
- * @summary Get storefront page by subdomain and path
- * @link /storefronts/subdomain/:subdomain/pages/:path
- */
-export function useGetStorefrontsSubdomainSubdomainPagesPathSuspense<
- TData = GetStorefrontsSubdomainSubdomainPagesPath["response"],
- TQueryKey extends
- QueryKey = GetStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey,
->(
- subdomain: GetStorefrontsSubdomainSubdomainPagesPathPathParams["subdomain"],
- path: GetStorefrontsSubdomainSubdomainPagesPathPathParams["path"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetStorefrontsSubdomainSubdomainPagesPath["response"],
- GetStorefrontsSubdomainSubdomainPagesPath["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetStorefrontsSubdomainSubdomainPagesPath["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainPagesPath["error"]
-> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryKey(subdomain, path);
- const query = useSuspenseQuery({
- ...(getStorefrontsSubdomainSubdomainPagesPathSuspenseQueryOptions(
- subdomain,
- path,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetStorefrontsSubdomainSubdomainPagesPath["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetTransactionByTransactionItem.ts b/src/phoenix-generated/hooks/useGetTransactionByTransactionItem.ts
deleted file mode 100644
index a463bb25..00000000
--- a/src/phoenix-generated/hooks/useGetTransactionByTransactionItem.ts
+++ /dev/null
@@ -1,187 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetTransactionByTransactionItem400,
- GetTransactionByTransactionItem401,
- GetTransactionByTransactionItem404,
- GetTransactionByTransactionItem500,
- GetTransactionByTransactionItemPathParams,
- GetTransactionByTransactionItemQueryResponse,
-} from "../types/GetTransactionByTransactionItem";
-
-type GetTransactionByTransactionItemClient = typeof client<
- GetTransactionByTransactionItemQueryResponse,
- | GetTransactionByTransactionItem400
- | GetTransactionByTransactionItem401
- | GetTransactionByTransactionItem404
- | GetTransactionByTransactionItem500,
- never
->;
-type GetTransactionByTransactionItem = {
- data: GetTransactionByTransactionItemQueryResponse;
- error:
- | GetTransactionByTransactionItem400
- | GetTransactionByTransactionItem401
- | GetTransactionByTransactionItem404
- | GetTransactionByTransactionItem500;
- request: never;
- pathParams: GetTransactionByTransactionItemPathParams;
- queryParams: never;
- headerParams: never;
- response: GetTransactionByTransactionItemQueryResponse;
- client: {
- parameters: Partial<Parameters<GetTransactionByTransactionItemClient>[0]>;
- return: Awaited<ReturnType<GetTransactionByTransactionItemClient>>;
- };
-};
-export const getTransactionByTransactionItemQueryKey = (
- id: GetTransactionByTransactionItemPathParams["id"],
-) =>
- [{ url: "/transaction/transaction-item/:id", params: { id: id } }] as const;
-export type GetTransactionByTransactionItemQueryKey = ReturnType<
- typeof getTransactionByTransactionItemQueryKey
->;
-export function getTransactionByTransactionItemQueryOptions(
- id: GetTransactionByTransactionItemPathParams["id"],
- options: GetTransactionByTransactionItem["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionByTransactionItemQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionByTransactionItem["data"],
- GetTransactionByTransactionItem["error"]
- >({
- method: "get",
- url: `/transaction/transaction-item/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction by transaction item ID
- * @summary Get transaction by transaction item
- * @link /transaction/transaction-item/:id
- */
-export function useGetTransactionByTransactionItem<
- TData = GetTransactionByTransactionItem["response"],
- TQueryData = GetTransactionByTransactionItem["response"],
- TQueryKey extends QueryKey = GetTransactionByTransactionItemQueryKey,
->(
- id: GetTransactionByTransactionItemPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetTransactionByTransactionItem["response"],
- GetTransactionByTransactionItem["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetTransactionByTransactionItem["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetTransactionByTransactionItem["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getTransactionByTransactionItemQueryKey(id);
- const query = useQuery({
- ...(getTransactionByTransactionItemQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetTransactionByTransactionItem["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getTransactionByTransactionItemSuspenseQueryKey = (
- id: GetTransactionByTransactionItemPathParams["id"],
-) =>
- [{ url: "/transaction/transaction-item/:id", params: { id: id } }] as const;
-export type GetTransactionByTransactionItemSuspenseQueryKey = ReturnType<
- typeof getTransactionByTransactionItemSuspenseQueryKey
->;
-export function getTransactionByTransactionItemSuspenseQueryOptions(
- id: GetTransactionByTransactionItemPathParams["id"],
- options: GetTransactionByTransactionItem["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionByTransactionItemSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionByTransactionItem["data"],
- GetTransactionByTransactionItem["error"]
- >({
- method: "get",
- url: `/transaction/transaction-item/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction by transaction item ID
- * @summary Get transaction by transaction item
- * @link /transaction/transaction-item/:id
- */
-export function useGetTransactionByTransactionItemSuspense<
- TData = GetTransactionByTransactionItem["response"],
- TQueryKey extends QueryKey = GetTransactionByTransactionItemSuspenseQueryKey,
->(
- id: GetTransactionByTransactionItemPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetTransactionByTransactionItem["response"],
- GetTransactionByTransactionItem["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetTransactionByTransactionItem["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetTransactionByTransactionItem["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ??
- getTransactionByTransactionItemSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getTransactionByTransactionItemSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<
- TData,
- GetTransactionByTransactionItem["error"]
- > & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetTransactionId.ts b/src/phoenix-generated/hooks/useGetTransactionId.ts
deleted file mode 100644
index 99631f1b..00000000
--- a/src/phoenix-generated/hooks/useGetTransactionId.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetTransactionId400,
- GetTransactionId401,
- GetTransactionId404,
- GetTransactionId500,
- GetTransactionIdPathParams,
- GetTransactionIdQueryResponse,
-} from "../types/GetTransactionId";
-
-type GetTransactionIdClient = typeof client<
- GetTransactionIdQueryResponse,
- | GetTransactionId400
- | GetTransactionId401
- | GetTransactionId404
- | GetTransactionId500,
- never
->;
-type GetTransactionId = {
- data: GetTransactionIdQueryResponse;
- error:
- | GetTransactionId400
- | GetTransactionId401
- | GetTransactionId404
- | GetTransactionId500;
- request: never;
- pathParams: GetTransactionIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetTransactionIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetTransactionIdClient>[0]>;
- return: Awaited<ReturnType<GetTransactionIdClient>>;
- };
-};
-export const getTransactionIdQueryKey = (
- id: GetTransactionIdPathParams["id"],
-) => [{ url: "/transaction/:id", params: { id: id } }] as const;
-export type GetTransactionIdQueryKey = ReturnType<
- typeof getTransactionIdQueryKey
->;
-export function getTransactionIdQueryOptions(
- id: GetTransactionIdPathParams["id"],
- options: GetTransactionId["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionIdQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionId["data"],
- GetTransactionId["error"]
- >({
- method: "get",
- url: `/transaction/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction by ID
- * @summary Get transaction
- * @link /transaction/:id
- */
-export function useGetTransactionId<
- TData = GetTransactionId["response"],
- TQueryData = GetTransactionId["response"],
- TQueryKey extends QueryKey = GetTransactionIdQueryKey,
->(
- id: GetTransactionIdPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetTransactionId["response"],
- GetTransactionId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetTransactionId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetTransactionId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getTransactionIdQueryKey(id);
- const query = useQuery({
- ...(getTransactionIdQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetTransactionId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getTransactionIdSuspenseQueryKey = (
- id: GetTransactionIdPathParams["id"],
-) => [{ url: "/transaction/:id", params: { id: id } }] as const;
-export type GetTransactionIdSuspenseQueryKey = ReturnType<
- typeof getTransactionIdSuspenseQueryKey
->;
-export function getTransactionIdSuspenseQueryOptions(
- id: GetTransactionIdPathParams["id"],
- options: GetTransactionId["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionIdSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionId["data"],
- GetTransactionId["error"]
- >({
- method: "get",
- url: `/transaction/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction by ID
- * @summary Get transaction
- * @link /transaction/:id
- */
-export function useGetTransactionIdSuspense<
- TData = GetTransactionId["response"],
- TQueryKey extends QueryKey = GetTransactionIdSuspenseQueryKey,
->(
- id: GetTransactionIdPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetTransactionId["response"],
- GetTransactionId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetTransactionId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetTransactionId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getTransactionIdSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getTransactionIdSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetTransactionId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetTransactionItemId.ts b/src/phoenix-generated/hooks/useGetTransactionItemId.ts
deleted file mode 100644
index 4afb90e4..00000000
--- a/src/phoenix-generated/hooks/useGetTransactionItemId.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetTransactionItemId400,
- GetTransactionItemId401,
- GetTransactionItemId404,
- GetTransactionItemId500,
- GetTransactionItemIdPathParams,
- GetTransactionItemIdQueryResponse,
-} from "../types/GetTransactionItemId";
-
-type GetTransactionItemIdClient = typeof client<
- GetTransactionItemIdQueryResponse,
- | GetTransactionItemId400
- | GetTransactionItemId401
- | GetTransactionItemId404
- | GetTransactionItemId500,
- never
->;
-type GetTransactionItemId = {
- data: GetTransactionItemIdQueryResponse;
- error:
- | GetTransactionItemId400
- | GetTransactionItemId401
- | GetTransactionItemId404
- | GetTransactionItemId500;
- request: never;
- pathParams: GetTransactionItemIdPathParams;
- queryParams: never;
- headerParams: never;
- response: GetTransactionItemIdQueryResponse;
- client: {
- parameters: Partial<Parameters<GetTransactionItemIdClient>[0]>;
- return: Awaited<ReturnType<GetTransactionItemIdClient>>;
- };
-};
-export const getTransactionItemIdQueryKey = (
- id: GetTransactionItemIdPathParams["id"],
-) => [{ url: "/transaction-item/:id", params: { id: id } }] as const;
-export type GetTransactionItemIdQueryKey = ReturnType<
- typeof getTransactionItemIdQueryKey
->;
-export function getTransactionItemIdQueryOptions(
- id: GetTransactionItemIdPathParams["id"],
- options: GetTransactionItemId["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionItemIdQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionItemId["data"],
- GetTransactionItemId["error"]
- >({
- method: "get",
- url: `/transaction-item/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction item by ID
- * @summary Get transaction item
- * @link /transaction-item/:id
- */
-export function useGetTransactionItemId<
- TData = GetTransactionItemId["response"],
- TQueryData = GetTransactionItemId["response"],
- TQueryKey extends QueryKey = GetTransactionItemIdQueryKey,
->(
- id: GetTransactionItemIdPathParams["id"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetTransactionItemId["response"],
- GetTransactionItemId["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetTransactionItemId["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetTransactionItemId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getTransactionItemIdQueryKey(id);
- const query = useQuery({
- ...(getTransactionItemIdQueryOptions(
- id,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetTransactionItemId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getTransactionItemIdSuspenseQueryKey = (
- id: GetTransactionItemIdPathParams["id"],
-) => [{ url: "/transaction-item/:id", params: { id: id } }] as const;
-export type GetTransactionItemIdSuspenseQueryKey = ReturnType<
- typeof getTransactionItemIdSuspenseQueryKey
->;
-export function getTransactionItemIdSuspenseQueryOptions(
- id: GetTransactionItemIdPathParams["id"],
- options: GetTransactionItemId["client"]["parameters"] = {},
-) {
- const queryKey = getTransactionItemIdSuspenseQueryKey(id);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetTransactionItemId["data"],
- GetTransactionItemId["error"]
- >({
- method: "get",
- url: `/transaction-item/${id}`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get transaction item by ID
- * @summary Get transaction item
- * @link /transaction-item/:id
- */
-export function useGetTransactionItemIdSuspense<
- TData = GetTransactionItemId["response"],
- TQueryKey extends QueryKey = GetTransactionItemIdSuspenseQueryKey,
->(
- id: GetTransactionItemIdPathParams["id"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetTransactionItemId["response"],
- GetTransactionItemId["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetTransactionItemId["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetTransactionItemId["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getTransactionItemIdSuspenseQueryKey(id);
- const query = useSuspenseQuery({
- ...(getTransactionItemIdSuspenseQueryOptions(
- id,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetTransactionItemId["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetWebsocketConnections.ts b/src/phoenix-generated/hooks/useGetWebsocketConnections.ts
deleted file mode 100644
index fd2bcdb3..00000000
--- a/src/phoenix-generated/hooks/useGetWebsocketConnections.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetWebsocketConnections400,
- GetWebsocketConnections401,
- GetWebsocketConnections500,
- GetWebsocketConnectionsQueryParams,
- GetWebsocketConnectionsQueryResponse,
-} from "../types/GetWebsocketConnections";
-
-type GetWebsocketConnectionsClient = typeof client<
- GetWebsocketConnectionsQueryResponse,
- | GetWebsocketConnections400
- | GetWebsocketConnections401
- | GetWebsocketConnections500,
- never
->;
-type GetWebsocketConnections = {
- data: GetWebsocketConnectionsQueryResponse;
- error:
- | GetWebsocketConnections400
- | GetWebsocketConnections401
- | GetWebsocketConnections500;
- request: never;
- pathParams: never;
- queryParams: GetWebsocketConnectionsQueryParams;
- headerParams: never;
- response: GetWebsocketConnectionsQueryResponse;
- client: {
- parameters: Partial<Parameters<GetWebsocketConnectionsClient>[0]>;
- return: Awaited<ReturnType<GetWebsocketConnectionsClient>>;
- };
-};
-export const getWebsocketConnectionsQueryKey = (
- params: GetWebsocketConnections["queryParams"],
-) => [{ url: "/websocket/connection" }, ...(params ? [params] : [])] as const;
-export type GetWebsocketConnectionsQueryKey = ReturnType<
- typeof getWebsocketConnectionsQueryKey
->;
-export function getWebsocketConnectionsQueryOptions(
- params: GetWebsocketConnections["queryParams"],
- options: GetWebsocketConnections["client"]["parameters"] = {},
-) {
- const queryKey = getWebsocketConnectionsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetWebsocketConnections["data"],
- GetWebsocketConnections["error"]
- >({
- method: "get",
- url: `/websocket/connection`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get websocket connections
- * @summary Get websocket connections
- * @link /websocket/connection
- */
-export function useGetWebsocketConnections<
- TData = GetWebsocketConnections["response"],
- TQueryData = GetWebsocketConnections["response"],
- TQueryKey extends QueryKey = GetWebsocketConnectionsQueryKey,
->(
- params: GetWebsocketConnections["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetWebsocketConnections["response"],
- GetWebsocketConnections["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetWebsocketConnections["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetWebsocketConnections["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getWebsocketConnectionsQueryKey(params);
- const query = useQuery({
- ...(getWebsocketConnectionsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetWebsocketConnections["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getWebsocketConnectionsSuspenseQueryKey = (
- params: GetWebsocketConnections["queryParams"],
-) => [{ url: "/websocket/connection" }, ...(params ? [params] : [])] as const;
-export type GetWebsocketConnectionsSuspenseQueryKey = ReturnType<
- typeof getWebsocketConnectionsSuspenseQueryKey
->;
-export function getWebsocketConnectionsSuspenseQueryOptions(
- params: GetWebsocketConnections["queryParams"],
- options: GetWebsocketConnections["client"]["parameters"] = {},
-) {
- const queryKey = getWebsocketConnectionsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetWebsocketConnections["data"],
- GetWebsocketConnections["error"]
- >({
- method: "get",
- url: `/websocket/connection`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get websocket connections
- * @summary Get websocket connections
- * @link /websocket/connection
- */
-export function useGetWebsocketConnectionsSuspense<
- TData = GetWebsocketConnections["response"],
- TQueryKey extends QueryKey = GetWebsocketConnectionsSuspenseQueryKey,
->(
- params: GetWebsocketConnections["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetWebsocketConnections["response"],
- GetWebsocketConnections["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetWebsocketConnections["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetWebsocketConnections["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getWebsocketConnectionsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(getWebsocketConnectionsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetWebsocketConnections["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useGetWebsocketMessage.ts b/src/phoenix-generated/hooks/useGetWebsocketMessage.ts
deleted file mode 100644
index 705a1de0..00000000
--- a/src/phoenix-generated/hooks/useGetWebsocketMessage.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- GetWebsocketMessage400,
- GetWebsocketMessage401,
- GetWebsocketMessage404,
- GetWebsocketMessage500,
- GetWebsocketMessageQueryResponse,
-} from "../types/GetWebsocketMessage";
-
-type GetWebsocketMessageClient = typeof client<
- GetWebsocketMessageQueryResponse,
- | GetWebsocketMessage400
- | GetWebsocketMessage401
- | GetWebsocketMessage404
- | GetWebsocketMessage500,
- never
->;
-type GetWebsocketMessage = {
- data: GetWebsocketMessageQueryResponse;
- error:
- | GetWebsocketMessage400
- | GetWebsocketMessage401
- | GetWebsocketMessage404
- | GetWebsocketMessage500;
- request: never;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: GetWebsocketMessageQueryResponse;
- client: {
- parameters: Partial<Parameters<GetWebsocketMessageClient>[0]>;
- return: Awaited<ReturnType<GetWebsocketMessageClient>>;
- };
-};
-export const getWebsocketMessageQueryKey = () =>
- [{ url: "/websocket/message" }] as const;
-export type GetWebsocketMessageQueryKey = ReturnType<
- typeof getWebsocketMessageQueryKey
->;
-export function getWebsocketMessageQueryOptions(
- options: GetWebsocketMessage["client"]["parameters"] = {},
-) {
- const queryKey = getWebsocketMessageQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetWebsocketMessage["data"],
- GetWebsocketMessage["error"]
- >({
- method: "get",
- url: `/websocket/message`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get websocket message
- * @summary Get websocket message (This isn't implemented yet, emitted for swagger type)
- * @link /websocket/message
- */
-export function useGetWebsocketMessage<
- TData = GetWebsocketMessage["response"],
- TQueryData = GetWebsocketMessage["response"],
- TQueryKey extends QueryKey = GetWebsocketMessageQueryKey,
->(
- options: {
- query?: Partial<
- QueryObserverOptions<
- GetWebsocketMessage["response"],
- GetWebsocketMessage["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: GetWebsocketMessage["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, GetWebsocketMessage["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? getWebsocketMessageQueryKey();
- const query = useQuery({
- ...(getWebsocketMessageQueryOptions(
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, GetWebsocketMessage["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const getWebsocketMessageSuspenseQueryKey = () =>
- [{ url: "/websocket/message" }] as const;
-export type GetWebsocketMessageSuspenseQueryKey = ReturnType<
- typeof getWebsocketMessageSuspenseQueryKey
->;
-export function getWebsocketMessageSuspenseQueryOptions(
- options: GetWebsocketMessage["client"]["parameters"] = {},
-) {
- const queryKey = getWebsocketMessageSuspenseQueryKey();
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- GetWebsocketMessage["data"],
- GetWebsocketMessage["error"]
- >({
- method: "get",
- url: `/websocket/message`,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description Get websocket message
- * @summary Get websocket message (This isn't implemented yet, emitted for swagger type)
- * @link /websocket/message
- */
-export function useGetWebsocketMessageSuspense<
- TData = GetWebsocketMessage["response"],
- TQueryKey extends QueryKey = GetWebsocketMessageSuspenseQueryKey,
->(
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- GetWebsocketMessage["response"],
- GetWebsocketMessage["error"],
- TData,
- TQueryKey
- >
- >;
- client?: GetWebsocketMessage["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, GetWebsocketMessage["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? getWebsocketMessageSuspenseQueryKey();
- const query = useSuspenseQuery({
- ...(getWebsocketMessageSuspenseQueryOptions(
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, GetWebsocketMessage["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListFulfillments.ts b/src/phoenix-generated/hooks/useListFulfillments.ts
deleted file mode 100644
index 20961b46..00000000
--- a/src/phoenix-generated/hooks/useListFulfillments.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListFulfillments400,
- ListFulfillments401,
- ListFulfillments500,
- ListFulfillmentsQueryParams,
- ListFulfillmentsQueryResponse,
-} from "../types/ListFulfillments";
-
-type ListFulfillmentsClient = typeof client<
- ListFulfillmentsQueryResponse,
- ListFulfillments400 | ListFulfillments401 | ListFulfillments500,
- never
->;
-type ListFulfillments = {
- data: ListFulfillmentsQueryResponse;
- error: ListFulfillments400 | ListFulfillments401 | ListFulfillments500;
- request: never;
- pathParams: never;
- queryParams: ListFulfillmentsQueryParams;
- headerParams: never;
- response: ListFulfillmentsQueryResponse;
- client: {
- parameters: Partial<Parameters<ListFulfillmentsClient>[0]>;
- return: Awaited<ReturnType<ListFulfillmentsClient>>;
- };
-};
-export const listFulfillmentsQueryKey = (
- params?: ListFulfillments["queryParams"],
-) => [{ url: "/fulfillment" }, ...(params ? [params] : [])] as const;
-export type ListFulfillmentsQueryKey = ReturnType<
- typeof listFulfillmentsQueryKey
->;
-export function listFulfillmentsQueryOptions(
- params?: ListFulfillments["queryParams"],
- options: ListFulfillments["client"]["parameters"] = {},
-) {
- const queryKey = listFulfillmentsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListFulfillments["data"],
- ListFulfillments["error"]
- >({
- method: "get",
- url: `/fulfillment`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List fulfillments with optional filtering
- * @summary List fulfillments
- * @link /fulfillment
- */
-export function useListFulfillments<
- TData = ListFulfillments["response"],
- TQueryData = ListFulfillments["response"],
- TQueryKey extends QueryKey = ListFulfillmentsQueryKey,
->(
- params?: ListFulfillments["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListFulfillments["response"],
- ListFulfillments["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListFulfillments["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListFulfillments["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? listFulfillmentsQueryKey(params);
- const query = useQuery({
- ...(listFulfillmentsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListFulfillments["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listFulfillmentsSuspenseQueryKey = (
- params?: ListFulfillments["queryParams"],
-) => [{ url: "/fulfillment" }, ...(params ? [params] : [])] as const;
-export type ListFulfillmentsSuspenseQueryKey = ReturnType<
- typeof listFulfillmentsSuspenseQueryKey
->;
-export function listFulfillmentsSuspenseQueryOptions(
- params?: ListFulfillments["queryParams"],
- options: ListFulfillments["client"]["parameters"] = {},
-) {
- const queryKey = listFulfillmentsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListFulfillments["data"],
- ListFulfillments["error"]
- >({
- method: "get",
- url: `/fulfillment`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List fulfillments with optional filtering
- * @summary List fulfillments
- * @link /fulfillment
- */
-export function useListFulfillmentsSuspense<
- TData = ListFulfillments["response"],
- TQueryKey extends QueryKey = ListFulfillmentsSuspenseQueryKey,
->(
- params?: ListFulfillments["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListFulfillments["response"],
- ListFulfillments["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListFulfillments["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListFulfillments["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listFulfillmentsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listFulfillmentsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListFulfillments["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListLoyaltyCustomers.ts b/src/phoenix-generated/hooks/useListLoyaltyCustomers.ts
deleted file mode 100644
index 74bd1383..00000000
--- a/src/phoenix-generated/hooks/useListLoyaltyCustomers.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListLoyaltyCustomers400,
- ListLoyaltyCustomers401,
- ListLoyaltyCustomers422,
- ListLoyaltyCustomers500,
- ListLoyaltyCustomersQueryParams,
- ListLoyaltyCustomersQueryResponse,
-} from "../types/ListLoyaltyCustomers";
-
-type ListLoyaltyCustomersClient = typeof client<
- ListLoyaltyCustomersQueryResponse,
- | ListLoyaltyCustomers400
- | ListLoyaltyCustomers401
- | ListLoyaltyCustomers422
- | ListLoyaltyCustomers500,
- never
->;
-type ListLoyaltyCustomers = {
- data: ListLoyaltyCustomersQueryResponse;
- error:
- | ListLoyaltyCustomers400
- | ListLoyaltyCustomers401
- | ListLoyaltyCustomers422
- | ListLoyaltyCustomers500;
- request: never;
- pathParams: never;
- queryParams: ListLoyaltyCustomersQueryParams;
- headerParams: never;
- response: ListLoyaltyCustomersQueryResponse;
- client: {
- parameters: Partial<Parameters<ListLoyaltyCustomersClient>[0]>;
- return: Awaited<ReturnType<ListLoyaltyCustomersClient>>;
- };
-};
-export const listLoyaltyCustomersQueryKey = (
- params?: ListLoyaltyCustomers["queryParams"],
-) => [{ url: "/loyalty-customer" }, ...(params ? [params] : [])] as const;
-export type ListLoyaltyCustomersQueryKey = ReturnType<
- typeof listLoyaltyCustomersQueryKey
->;
-export function listLoyaltyCustomersQueryOptions(
- params?: ListLoyaltyCustomers["queryParams"],
- options: ListLoyaltyCustomers["client"]["parameters"] = {},
-) {
- const queryKey = listLoyaltyCustomersQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListLoyaltyCustomers["data"],
- ListLoyaltyCustomers["error"]
- >({
- method: "get",
- url: `/loyalty-customer`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List loyalty customers
- * @summary List loyalty customers
- * @link /loyalty-customer
- */
-export function useListLoyaltyCustomers<
- TData = ListLoyaltyCustomers["response"],
- TQueryData = ListLoyaltyCustomers["response"],
- TQueryKey extends QueryKey = ListLoyaltyCustomersQueryKey,
->(
- params?: ListLoyaltyCustomers["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListLoyaltyCustomers["response"],
- ListLoyaltyCustomers["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListLoyaltyCustomers["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListLoyaltyCustomers["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listLoyaltyCustomersQueryKey(params);
- const query = useQuery({
- ...(listLoyaltyCustomersQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListLoyaltyCustomers["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listLoyaltyCustomersSuspenseQueryKey = (
- params?: ListLoyaltyCustomers["queryParams"],
-) => [{ url: "/loyalty-customer" }, ...(params ? [params] : [])] as const;
-export type ListLoyaltyCustomersSuspenseQueryKey = ReturnType<
- typeof listLoyaltyCustomersSuspenseQueryKey
->;
-export function listLoyaltyCustomersSuspenseQueryOptions(
- params?: ListLoyaltyCustomers["queryParams"],
- options: ListLoyaltyCustomers["client"]["parameters"] = {},
-) {
- const queryKey = listLoyaltyCustomersSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListLoyaltyCustomers["data"],
- ListLoyaltyCustomers["error"]
- >({
- method: "get",
- url: `/loyalty-customer`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List loyalty customers
- * @summary List loyalty customers
- * @link /loyalty-customer
- */
-export function useListLoyaltyCustomersSuspense<
- TData = ListLoyaltyCustomers["response"],
- TQueryKey extends QueryKey = ListLoyaltyCustomersSuspenseQueryKey,
->(
- params?: ListLoyaltyCustomers["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListLoyaltyCustomers["response"],
- ListLoyaltyCustomers["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListLoyaltyCustomers["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListLoyaltyCustomers["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listLoyaltyCustomersSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listLoyaltyCustomersSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListLoyaltyCustomers["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListOrderItemDecisions.ts b/src/phoenix-generated/hooks/useListOrderItemDecisions.ts
deleted file mode 100644
index 3718a408..00000000
--- a/src/phoenix-generated/hooks/useListOrderItemDecisions.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListOrderItemDecisions400,
- ListOrderItemDecisions401,
- ListOrderItemDecisions500,
- ListOrderItemDecisionsQueryParams,
- ListOrderItemDecisionsQueryResponse,
-} from "../types/ListOrderItemDecisions";
-
-type ListOrderItemDecisionsClient = typeof client<
- ListOrderItemDecisionsQueryResponse,
- | ListOrderItemDecisions400
- | ListOrderItemDecisions401
- | ListOrderItemDecisions500,
- never
->;
-type ListOrderItemDecisions = {
- data: ListOrderItemDecisionsQueryResponse;
- error:
- | ListOrderItemDecisions400
- | ListOrderItemDecisions401
- | ListOrderItemDecisions500;
- request: never;
- pathParams: never;
- queryParams: ListOrderItemDecisionsQueryParams;
- headerParams: never;
- response: ListOrderItemDecisionsQueryResponse;
- client: {
- parameters: Partial<Parameters<ListOrderItemDecisionsClient>[0]>;
- return: Awaited<ReturnType<ListOrderItemDecisionsClient>>;
- };
-};
-export const listOrderItemDecisionsQueryKey = (
- params?: ListOrderItemDecisions["queryParams"],
-) => [{ url: "/order-item-decisions" }, ...(params ? [params] : [])] as const;
-export type ListOrderItemDecisionsQueryKey = ReturnType<
- typeof listOrderItemDecisionsQueryKey
->;
-export function listOrderItemDecisionsQueryOptions(
- params?: ListOrderItemDecisions["queryParams"],
- options: ListOrderItemDecisions["client"]["parameters"] = {},
-) {
- const queryKey = listOrderItemDecisionsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListOrderItemDecisions["data"],
- ListOrderItemDecisions["error"]
- >({
- method: "get",
- url: `/order-item-decisions`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List order item decisions with optional filtering
- * @summary List order item decisions
- * @link /order-item-decisions
- */
-export function useListOrderItemDecisions<
- TData = ListOrderItemDecisions["response"],
- TQueryData = ListOrderItemDecisions["response"],
- TQueryKey extends QueryKey = ListOrderItemDecisionsQueryKey,
->(
- params?: ListOrderItemDecisions["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListOrderItemDecisions["response"],
- ListOrderItemDecisions["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListOrderItemDecisions["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListOrderItemDecisions["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listOrderItemDecisionsQueryKey(params);
- const query = useQuery({
- ...(listOrderItemDecisionsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListOrderItemDecisions["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listOrderItemDecisionsSuspenseQueryKey = (
- params?: ListOrderItemDecisions["queryParams"],
-) => [{ url: "/order-item-decisions" }, ...(params ? [params] : [])] as const;
-export type ListOrderItemDecisionsSuspenseQueryKey = ReturnType<
- typeof listOrderItemDecisionsSuspenseQueryKey
->;
-export function listOrderItemDecisionsSuspenseQueryOptions(
- params?: ListOrderItemDecisions["queryParams"],
- options: ListOrderItemDecisions["client"]["parameters"] = {},
-) {
- const queryKey = listOrderItemDecisionsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListOrderItemDecisions["data"],
- ListOrderItemDecisions["error"]
- >({
- method: "get",
- url: `/order-item-decisions`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List order item decisions with optional filtering
- * @summary List order item decisions
- * @link /order-item-decisions
- */
-export function useListOrderItemDecisionsSuspense<
- TData = ListOrderItemDecisions["response"],
- TQueryKey extends QueryKey = ListOrderItemDecisionsSuspenseQueryKey,
->(
- params?: ListOrderItemDecisions["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListOrderItemDecisions["response"],
- ListOrderItemDecisions["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListOrderItemDecisions["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListOrderItemDecisions["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listOrderItemDecisionsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listOrderItemDecisionsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListOrderItemDecisions["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListStorefronts.ts b/src/phoenix-generated/hooks/useListStorefronts.ts
deleted file mode 100644
index 1813a630..00000000
--- a/src/phoenix-generated/hooks/useListStorefronts.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListStorefronts401,
- ListStorefronts500,
- ListStorefrontsQueryParams,
- ListStorefrontsQueryResponse,
-} from "../types/ListStorefronts";
-
-type ListStorefrontsClient = typeof client<
- ListStorefrontsQueryResponse,
- ListStorefronts401 | ListStorefronts500,
- never
->;
-type ListStorefronts = {
- data: ListStorefrontsQueryResponse;
- error: ListStorefronts401 | ListStorefronts500;
- request: never;
- pathParams: never;
- queryParams: ListStorefrontsQueryParams;
- headerParams: never;
- response: ListStorefrontsQueryResponse;
- client: {
- parameters: Partial<Parameters<ListStorefrontsClient>[0]>;
- return: Awaited<ReturnType<ListStorefrontsClient>>;
- };
-};
-export const listStorefrontsQueryKey = (
- params?: ListStorefronts["queryParams"],
-) => [{ url: "/storefronts" }, ...(params ? [params] : [])] as const;
-export type ListStorefrontsQueryKey = ReturnType<
- typeof listStorefrontsQueryKey
->;
-export function listStorefrontsQueryOptions(
- params?: ListStorefronts["queryParams"],
- options: ListStorefronts["client"]["parameters"] = {},
-) {
- const queryKey = listStorefrontsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListStorefronts["data"],
- ListStorefronts["error"]
- >({
- method: "get",
- url: `/storefronts`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List storefronts with optional filtering by cohort_id and active status
- * @summary List storefronts
- * @link /storefronts
- */
-export function useListStorefronts<
- TData = ListStorefronts["response"],
- TQueryData = ListStorefronts["response"],
- TQueryKey extends QueryKey = ListStorefrontsQueryKey,
->(
- params?: ListStorefronts["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListStorefronts["response"],
- ListStorefronts["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListStorefronts["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListStorefronts["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? listStorefrontsQueryKey(params);
- const query = useQuery({
- ...(listStorefrontsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListStorefronts["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listStorefrontsSuspenseQueryKey = (
- params?: ListStorefronts["queryParams"],
-) => [{ url: "/storefronts" }, ...(params ? [params] : [])] as const;
-export type ListStorefrontsSuspenseQueryKey = ReturnType<
- typeof listStorefrontsSuspenseQueryKey
->;
-export function listStorefrontsSuspenseQueryOptions(
- params?: ListStorefronts["queryParams"],
- options: ListStorefronts["client"]["parameters"] = {},
-) {
- const queryKey = listStorefrontsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListStorefronts["data"],
- ListStorefronts["error"]
- >({
- method: "get",
- url: `/storefronts`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List storefronts with optional filtering by cohort_id and active status
- * @summary List storefronts
- * @link /storefronts
- */
-export function useListStorefrontsSuspense<
- TData = ListStorefronts["response"],
- TQueryKey extends QueryKey = ListStorefrontsSuspenseQueryKey,
->(
- params?: ListStorefronts["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListStorefronts["response"],
- ListStorefronts["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListStorefronts["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListStorefronts["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listStorefrontsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listStorefrontsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListStorefronts["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListTransactionItems.ts b/src/phoenix-generated/hooks/useListTransactionItems.ts
deleted file mode 100644
index 104454de..00000000
--- a/src/phoenix-generated/hooks/useListTransactionItems.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListTransactionItems400,
- ListTransactionItems401,
- ListTransactionItems500,
- ListTransactionItemsQueryParams,
- ListTransactionItemsQueryResponse,
-} from "../types/ListTransactionItems";
-
-type ListTransactionItemsClient = typeof client<
- ListTransactionItemsQueryResponse,
- ListTransactionItems400 | ListTransactionItems401 | ListTransactionItems500,
- never
->;
-type ListTransactionItems = {
- data: ListTransactionItemsQueryResponse;
- error:
- | ListTransactionItems400
- | ListTransactionItems401
- | ListTransactionItems500;
- request: never;
- pathParams: never;
- queryParams: ListTransactionItemsQueryParams;
- headerParams: never;
- response: ListTransactionItemsQueryResponse;
- client: {
- parameters: Partial<Parameters<ListTransactionItemsClient>[0]>;
- return: Awaited<ReturnType<ListTransactionItemsClient>>;
- };
-};
-export const listTransactionItemsQueryKey = (
- params?: ListTransactionItems["queryParams"],
-) => [{ url: "/transaction-item" }, ...(params ? [params] : [])] as const;
-export type ListTransactionItemsQueryKey = ReturnType<
- typeof listTransactionItemsQueryKey
->;
-export function listTransactionItemsQueryOptions(
- params?: ListTransactionItems["queryParams"],
- options: ListTransactionItems["client"]["parameters"] = {},
-) {
- const queryKey = listTransactionItemsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListTransactionItems["data"],
- ListTransactionItems["error"]
- >({
- method: "get",
- url: `/transaction-item`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List transaction items
- * @summary List transaction items
- * @link /transaction-item
- */
-export function useListTransactionItems<
- TData = ListTransactionItems["response"],
- TQueryData = ListTransactionItems["response"],
- TQueryKey extends QueryKey = ListTransactionItemsQueryKey,
->(
- params?: ListTransactionItems["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListTransactionItems["response"],
- ListTransactionItems["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListTransactionItems["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListTransactionItems["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listTransactionItemsQueryKey(params);
- const query = useQuery({
- ...(listTransactionItemsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListTransactionItems["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listTransactionItemsSuspenseQueryKey = (
- params?: ListTransactionItems["queryParams"],
-) => [{ url: "/transaction-item" }, ...(params ? [params] : [])] as const;
-export type ListTransactionItemsSuspenseQueryKey = ReturnType<
- typeof listTransactionItemsSuspenseQueryKey
->;
-export function listTransactionItemsSuspenseQueryOptions(
- params?: ListTransactionItems["queryParams"],
- options: ListTransactionItems["client"]["parameters"] = {},
-) {
- const queryKey = listTransactionItemsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListTransactionItems["data"],
- ListTransactionItems["error"]
- >({
- method: "get",
- url: `/transaction-item`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List transaction items
- * @summary List transaction items
- * @link /transaction-item
- */
-export function useListTransactionItemsSuspense<
- TData = ListTransactionItems["response"],
- TQueryKey extends QueryKey = ListTransactionItemsSuspenseQueryKey,
->(
- params?: ListTransactionItems["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListTransactionItems["response"],
- ListTransactionItems["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListTransactionItems["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListTransactionItems["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listTransactionItemsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listTransactionItemsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListTransactionItems["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/useListTransactions.ts b/src/phoenix-generated/hooks/useListTransactions.ts
deleted file mode 100644
index 7e5861db..00000000
--- a/src/phoenix-generated/hooks/useListTransactions.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-import type {
- QueryKey,
- QueryObserverOptions,
- UseQueryResult,
- UseSuspenseQueryOptions,
- UseSuspenseQueryResult,
-} from "@tanstack/react-query";
-import {
- queryOptions,
- useQuery,
- useSuspenseQuery,
-} from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- ListTransactions400,
- ListTransactions401,
- ListTransactions500,
- ListTransactionsQueryParams,
- ListTransactionsQueryResponse,
-} from "../types/ListTransactions";
-
-type ListTransactionsClient = typeof client<
- ListTransactionsQueryResponse,
- ListTransactions400 | ListTransactions401 | ListTransactions500,
- never
->;
-type ListTransactions = {
- data: ListTransactionsQueryResponse;
- error: ListTransactions400 | ListTransactions401 | ListTransactions500;
- request: never;
- pathParams: never;
- queryParams: ListTransactionsQueryParams;
- headerParams: never;
- response: ListTransactionsQueryResponse;
- client: {
- parameters: Partial<Parameters<ListTransactionsClient>[0]>;
- return: Awaited<ReturnType<ListTransactionsClient>>;
- };
-};
-export const listTransactionsQueryKey = (
- params?: ListTransactions["queryParams"],
-) => [{ url: "/transaction" }, ...(params ? [params] : [])] as const;
-export type ListTransactionsQueryKey = ReturnType<
- typeof listTransactionsQueryKey
->;
-export function listTransactionsQueryOptions(
- params?: ListTransactions["queryParams"],
- options: ListTransactions["client"]["parameters"] = {},
-) {
- const queryKey = listTransactionsQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListTransactions["data"],
- ListTransactions["error"]
- >({
- method: "get",
- url: `/transaction`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List transactions
- * @summary List transactions
- * @link /transaction
- */
-export function useListTransactions<
- TData = ListTransactions["response"],
- TQueryData = ListTransactions["response"],
- TQueryKey extends QueryKey = ListTransactionsQueryKey,
->(
- params?: ListTransactions["queryParams"],
- options: {
- query?: Partial<
- QueryObserverOptions<
- ListTransactions["response"],
- ListTransactions["error"],
- TData,
- TQueryData,
- TQueryKey
- >
- >;
- client?: ListTransactions["client"]["parameters"];
- } = {},
-): UseQueryResult<TData, ListTransactions["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey = queryOptions?.queryKey ?? listTransactionsQueryKey(params);
- const query = useQuery({
- ...(listTransactionsQueryOptions(
- params,
- clientOptions,
- ) as unknown as QueryObserverOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<QueryObserverOptions, "queryKey">),
- }) as UseQueryResult<TData, ListTransactions["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
-export const listTransactionsSuspenseQueryKey = (
- params?: ListTransactions["queryParams"],
-) => [{ url: "/transaction" }, ...(params ? [params] : [])] as const;
-export type ListTransactionsSuspenseQueryKey = ReturnType<
- typeof listTransactionsSuspenseQueryKey
->;
-export function listTransactionsSuspenseQueryOptions(
- params?: ListTransactions["queryParams"],
- options: ListTransactions["client"]["parameters"] = {},
-) {
- const queryKey = listTransactionsSuspenseQueryKey(params);
- return queryOptions({
- queryKey,
- queryFn: async () => {
- const res = await client<
- ListTransactions["data"],
- ListTransactions["error"]
- >({
- method: "get",
- url: `/transaction`,
- params,
- ...options,
- });
- return res.data;
- },
- });
-}
-/**
- * @description List transactions
- * @summary List transactions
- * @link /transaction
- */
-export function useListTransactionsSuspense<
- TData = ListTransactions["response"],
- TQueryKey extends QueryKey = ListTransactionsSuspenseQueryKey,
->(
- params?: ListTransactions["queryParams"],
- options: {
- query?: Partial<
- UseSuspenseQueryOptions<
- ListTransactions["response"],
- ListTransactions["error"],
- TData,
- TQueryKey
- >
- >;
- client?: ListTransactions["client"]["parameters"];
- } = {},
-): UseSuspenseQueryResult<TData, ListTransactions["error"]> & {
- queryKey: TQueryKey;
-} {
- const { query: queryOptions, client: clientOptions = {} } = options ?? {};
- const queryKey =
- queryOptions?.queryKey ?? listTransactionsSuspenseQueryKey(params);
- const query = useSuspenseQuery({
- ...(listTransactionsSuspenseQueryOptions(
- params,
- clientOptions,
- ) as unknown as UseSuspenseQueryOptions),
- queryKey,
- ...(queryOptions as unknown as Omit<UseSuspenseQueryOptions, "queryKey">),
- }) as UseSuspenseQueryResult<TData, ListTransactions["error"]> & {
- queryKey: TQueryKey;
- };
- query.queryKey = queryKey as TQueryKey;
- return query;
-}
diff --git a/src/phoenix-generated/hooks/usePatchFulfillmentId.ts b/src/phoenix-generated/hooks/usePatchFulfillmentId.ts
deleted file mode 100644
index be6d98a3..00000000
--- a/src/phoenix-generated/hooks/usePatchFulfillmentId.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- PatchFulfillmentId400,
- PatchFulfillmentId401,
- PatchFulfillmentId404,
- PatchFulfillmentId422,
- PatchFulfillmentId500,
- PatchFulfillmentIdMutationRequest,
- PatchFulfillmentIdMutationResponse,
- PatchFulfillmentIdPathParams,
-} from "../types/PatchFulfillmentId";
-
-type PatchFulfillmentIdClient = typeof client<
- PatchFulfillmentIdMutationResponse,
- | PatchFulfillmentId400
- | PatchFulfillmentId401
- | PatchFulfillmentId404
- | PatchFulfillmentId422
- | PatchFulfillmentId500,
- PatchFulfillmentIdMutationRequest
->;
-type PatchFulfillmentId = {
- data: PatchFulfillmentIdMutationResponse;
- error:
- | PatchFulfillmentId400
- | PatchFulfillmentId401
- | PatchFulfillmentId404
- | PatchFulfillmentId422
- | PatchFulfillmentId500;
- request: PatchFulfillmentIdMutationRequest;
- pathParams: PatchFulfillmentIdPathParams;
- queryParams: never;
- headerParams: never;
- response: PatchFulfillmentIdMutationResponse;
- client: {
- parameters: Partial<Parameters<PatchFulfillmentIdClient>[0]>;
- return: Awaited<ReturnType<PatchFulfillmentIdClient>>;
- };
-};
-/**
- * @description Update an existing fulfillment
- * @summary Update fulfillment
- * @link /fulfillment/:id
- */
-export function usePatchFulfillmentId(
- options: {
- mutation?: UseMutationOptions<
- PatchFulfillmentId["response"],
- PatchFulfillmentId["error"],
- {
- id: PatchFulfillmentIdPathParams["id"];
- data?: PatchFulfillmentId["request"];
- }
- >;
- client?: PatchFulfillmentId["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ id, data }) => {
- const res = await client<
- PatchFulfillmentId["data"],
- PatchFulfillmentId["error"],
- PatchFulfillmentId["request"]
- >({
- method: "patch",
- url: `/fulfillment/${id}`,
- data,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/usePatchStorefrontsId.ts b/src/phoenix-generated/hooks/usePatchStorefrontsId.ts
deleted file mode 100644
index 18f68bd4..00000000
--- a/src/phoenix-generated/hooks/usePatchStorefrontsId.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- PatchStorefrontsId400,
- PatchStorefrontsId401,
- PatchStorefrontsId404,
- PatchStorefrontsId422,
- PatchStorefrontsId500,
- PatchStorefrontsIdMutationRequest,
- PatchStorefrontsIdMutationResponse,
- PatchStorefrontsIdPathParams,
-} from "../types/PatchStorefrontsId";
-
-type PatchStorefrontsIdClient = typeof client<
- PatchStorefrontsIdMutationResponse,
- | PatchStorefrontsId400
- | PatchStorefrontsId401
- | PatchStorefrontsId404
- | PatchStorefrontsId422
- | PatchStorefrontsId500,
- PatchStorefrontsIdMutationRequest
->;
-type PatchStorefrontsId = {
- data: PatchStorefrontsIdMutationResponse;
- error:
- | PatchStorefrontsId400
- | PatchStorefrontsId401
- | PatchStorefrontsId404
- | PatchStorefrontsId422
- | PatchStorefrontsId500;
- request: PatchStorefrontsIdMutationRequest;
- pathParams: PatchStorefrontsIdPathParams;
- queryParams: never;
- headerParams: never;
- response: PatchStorefrontsIdMutationResponse;
- client: {
- parameters: Partial<Parameters<PatchStorefrontsIdClient>[0]>;
- return: Awaited<ReturnType<PatchStorefrontsIdClient>>;
- };
-};
-/**
- * @description Update an existing storefront
- * @summary Update storefront
- * @link /storefronts/:id
- */
-export function usePatchStorefrontsId(
- options: {
- mutation?: UseMutationOptions<
- PatchStorefrontsId["response"],
- PatchStorefrontsId["error"],
- {
- id: PatchStorefrontsIdPathParams["id"];
- data?: PatchStorefrontsId["request"];
- }
- >;
- client?: PatchStorefrontsId["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- return useMutation({
- mutationFn: async ({ id, data }) => {
- const res = await client<
- PatchStorefrontsId["data"],
- PatchStorefrontsId["error"],
- PatchStorefrontsId["request"]
- >({
- method: "patch",
- url: `/storefronts/${id}`,
- data,
- ...clientOptions,
- });
- return res.data;
- },
- ...mutationOptions,
- });
-}
diff --git a/src/phoenix-generated/hooks/usePostCustomer.ts b/src/phoenix-generated/hooks/usePostCustomer.ts
deleted file mode 100644
index 1d11b3e7..00000000
--- a/src/phoenix-generated/hooks/usePostCustomer.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import type { UseMutationOptions } from "@tanstack/react-query";
-import { useMutation } from "@tanstack/react-query";
-import client from "../../config/phoenix-client";
-import type {
- PostCustomer400,
- PostCustomer401,
- PostCustomer422,
- PostCustomer500,
- PostCustomerMutationRequest,
- PostCustomerMutationResponse,
-} from "../types/PostCustomer";
-
-type PostCustomerClient = typeof client<
- PostCustomerMutationResponse,
- PostCustomer400 | PostCustomer401 | PostCustomer422 | PostCustomer500,
- PostCustomerMutationRequest
->;
-type PostCustomer = {
- data: PostCustomerMutationResponse;
- error: PostCustomer400 | PostCustomer401 | PostCustomer422 | PostCustomer500;
- request: PostCustomerMutationRequest;
- pathParams: never;
- queryParams: never;
- headerParams: never;
- response: PostCustomerMutationResponse;
- client: {
- parameters: Partial<Parameters<PostCustomerClient>[0]>;
- return: Awaited<ReturnType<PostCustomerClient>>;
- };
-};
-/**
- * @description Create a new customer
- * @summary Create customer
- * @link /customer
- */
-export function usePostCustomer(
- options: {
- mutation?: UseMutationOptions<
- PostCustomer["response"],
- PostCustomer["error"],
- {
- data: PostCustomer["request"];
- }
- >;
- client?: PostCustomer["client"]["parameters"];
- } = {},
-) {
- const { mutation: mutationOptions, client: clientOptions = {} } =
- options ?? {};
- ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment