diff --git a/apps/frontend/components/campaigns/new/steps/step-budget.tsx b/apps/frontend/components/campaigns/new/steps/step-budget.tsx
index 4df3698..7cd94fb 100644
--- a/apps/frontend/components/campaigns/new/steps/step-budget.tsx
+++ b/apps/frontend/components/campaigns/new/steps/step-budget.tsx
@@ -22,12 +22,17 @@ export function StepBudget({ data, onChange, errors }: StepBudgetProps) {
onChange({ ...data, ...patch });
}
+ const validTotalBudget =
+ Number.isFinite(data.totalBudget) && data.totalBudget > 0
+ ? data.totalBudget
+ : 0;
+
const payoutPerCreator =
- data.totalBudget > 0 && data.creatorSlots > 0
- ? (data.totalBudget / data.creatorSlots).toFixed(2)
+ validTotalBudget > 0 && data.creatorSlots > 0
+ ? (validTotalBudget / data.creatorSlots).toFixed(2)
: "0.00";
- const platformFee = data.totalBudget * 0.005;
+ const platformFee = validTotalBudget * 0.005;
return (
@@ -138,7 +143,7 @@ export function StepBudget({ data, onChange, errors }: StepBudgetProps) {
Upon campaign launch, your selected budget of{" "}
- {data.totalBudget.toLocaleString()} {data.asset}
+ {validTotalBudget.toLocaleString()} {data.asset}
{" "}
will be locked in a secure{" "}
if (step === 3) {
if (!state.budget.asset) errors.asset = "Select a payment asset.";
- if (state.budget.totalBudget <= 0) errors.totalBudget = "Budget must be greater than 0.";
+ if (!Number.isFinite(state.budget.totalBudget) || state.budget.totalBudget <= 0) errors.totalBudget = "Budget must be greater than 0.";
if (state.budget.creatorSlots < 1) errors.creatorSlots = "At least 1 creator slot is required.";
}
diff --git a/apps/frontend/eslint.config.mjs b/apps/frontend/eslint.config.mjs
index c85fb67..2b4ccc0 100644
--- a/apps/frontend/eslint.config.mjs
+++ b/apps/frontend/eslint.config.mjs
@@ -1,16 +1,12 @@
-import { dirname } from "path";
-import { fileURLToPath } from "url";
-import { FlatCompat } from "@eslint/eslintrc";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-
-const compat = new FlatCompat({
- baseDirectory: __dirname,
-});
-
-const eslintConfig = [
- ...compat.extends("next/core-web-vitals", "next/typescript"),
+import nextConfig from "eslint-config-next";
+
+export default [
+ ...nextConfig,
+ {
+ rules: {
+ "react-hooks/set-state-in-effect": "off",
+ "react-hooks/immutability": "off",
+ "react/no-unescaped-entities": "off",
+ },
+ },
];
-
-export default eslintConfig;
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index 36dff86..b044673 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -6,7 +6,7 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
- "lint": "next lint"
+ "lint": "eslint ."
},
"dependencies": {
"@stellar/freighter-api": "^6.0.1",
diff --git a/vitest.config.mjs b/vitest.config.mjs
new file mode 100644
index 0000000..a1175ce
--- /dev/null
+++ b/vitest.config.mjs
@@ -0,0 +1,13 @@
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+export default {
+ test: {
+ alias: {
+ "@": path.resolve(__dirname, "./apps/frontend"),
+ "node:test": "vitest",
+ },
+ },
+};