Skip to content

Commit 30984de

Browse files
committed
fix: resolve all TypeScript errors and test failures from merged contributor PRs
- LiveCounter: close unclosed outer `if` block; remove duplicate `aria-label` - LiveCounter: remove duplicate `formatUSDCFixed` const declaration - StreamComparisonModal: rename non-existent `formatStreamAmount` → `formatStellarAmount` - stream/new: remove duplicate React import; remove unclosed `handleTemplateSelect` stub that was swallowing all component-level hooks and the JSX return; remove duplicate state declarations (duration, selectedToken×3, customTokenAddress, endDate, cliffDate); remove dead code after early return; fix unescaped JSX entities (`'`, `"`) - stream/new: add missing params to `handleTemplateSelect` signature - admin: remove duplicate `TreasuryBalance` import; replace undefined `ADMIN_WALLET` with `ADMIN_ADDRESSES.length > 0`; fix accidental `<strong>` text replacement - admin: remove orphaned `)}` from Emergency Pause section; close missing `)}` for non-admin note conditional - dashboard: add missing `getAllTags`/`getTagMap` imports from streamTags lib; add `Paused` to sort order map with `Record<string, number>` typing - dashboard: remove `{/* end My Streams tabpanel */}` JSX comment that broke ternary expression parsing - stream/[id]: add missing imports for `StreamTagEditor` and `getGiftMessage`; remove extra `</div>` that caused div-balance to go negative at line 1359 - sorostream mock: add `_streamId` param to `topUp` so bulk top-up compiles - streamHealth: change `<=` to `<` so the boundary (exactly 24 h) is "Active" - tests: fix `makeStream` helper to use fixed `NOW` constant instead of `Date.now()` - tests: replace hardcoded `/workspaces/…` paths with `process.cwd()` equivalents - tests: remove duplicate `useWallet` property in StreamActions mock - tests: replace string-index on typed locale objects with `Record<string, unknown>` - tests: use `waitFor` in WalletConnect disabled-while-connecting test
1 parent cfa3994 commit 30984de

13 files changed

Lines changed: 31 additions & 60 deletions

components/LiveCounter.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ function parseClaimable(value: string | number | bigint): number | null {
4040
return Number.isFinite(amount) && amount >= 0 ? amount : null;
4141
}
4242

43-
const formatUSDCFixed = (val: number) => (val / 10_000_000).toFixed(7);
44-
4543

4644
export default function LiveCounter({
4745
flowRate,
@@ -169,6 +167,7 @@ export default function LiveCounter({
169167
setAriaLabel(safeFormatUSDCFixed(displayValue));
170168
}, remaining);
171169
return () => clearTimeout(timer);
170+
}
172171
}, [displayValue, safeFormatUSDCFixed]);
173172

174173
return (
@@ -181,7 +180,6 @@ export default function LiveCounter({
181180
t("claimable", { val: ariaLabel }) +
182181
(isOptimistic ? t("pending_confirmation") : "")
183182
}
184-
aria-label={`Claimable: ${formatUSDCFixed(displayValue)} USDC`}
185183
>
186184
<span className={isOptimistic ? "text-yellow-400" : "text-green-600"}>
187185
{formatUSDC(displayValue)} USDC

components/StreamComparisonModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState, useEffect, useRef, useMemo } from "react";
44
import { useFocusTrap } from "@/src/lib/useFocusTrap";
55
import { useTranslations } from "@/src/lib/i18n";
66
import type { StreamData } from "@/src/lib/sorostream";
7-
import { formatStellarAmount, formatStreamAmount } from "@/src/lib/sorostream";
7+
import { formatStellarAmount } from "@/src/lib/sorostream";
88
import FederationName from "@/components/FederationName";
99

1010
interface StreamComparisonModalProps {
@@ -346,8 +346,8 @@ export default function StreamComparisonModal({
346346

347347
<ComparisonRow
348348
label={t("compare_amount")}
349-
current={formatStreamAmount(currentStream.deposit)}
350-
compared={formatStreamAmount(selectedStream.deposit)}
349+
current={formatStellarAmount(currentStream.deposit)}
350+
compared={formatStellarAmount(selectedStream.deposit)}
351351
highlighted={getDifference(
352352
currentStream.deposit,
353353
selectedStream.deposit

components/__tests__/NetReceivedDisplay.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { describe, it, expect } from "vitest";
33
describe("Net Received Display Feature", () => {
44
// Test 1: Verify the component exists and exports
55
it("should export NetReceivedDisplay component", async () => {
6-
const module = await import("@/components/NetReceivedDisplay");
7-
expect(module.default).toBeDefined();
6+
const mod = await import("@/components/NetReceivedDisplay");
7+
expect(mod.default).toBeDefined();
88
});
99

1010
// Test 2: Verify stream new page imports
1111
it("should have NetReceivedDisplay imported in stream new page", async () => {
1212
const fs = await import("fs/promises");
1313
const content = await fs.readFile(
14-
"/workspaces/sorostream-app/src/app/stream/new/page.tsx",
14+
`${process.cwd()}/src/app/stream/new/page.tsx`,
1515
"utf-8"
1616
);
1717

@@ -68,9 +68,9 @@ describe("Net Received Display Feature", () => {
6868

6969
const keys = ["net_received_label", "net_received_fee_desc"];
7070
keys.forEach((key) => {
71-
expect(en.default.stream_new[key]).toBeDefined();
72-
expect(pt.default.stream_new[key]).toBeDefined();
73-
expect(es.default.stream_new[key]).toBeDefined();
71+
expect((en.default.stream_new as Record<string, unknown>)[key]).toBeDefined();
72+
expect((pt.default.stream_new as Record<string, unknown>)[key]).toBeDefined();
73+
expect((es.default.stream_new as Record<string, unknown>)[key]).toBeDefined();
7474
});
7575
});
7676
});

components/__tests__/StreamActions.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ vi.mock('@/src/context/SettingsContext', () => ({
3333
}));
3434

3535
vi.mock('@/src/context/WalletContext', () => ({
36-
useWallet: () => ({ refetchBalance: vi.fn() }),
3736
useWallet: () => ({ refetchBalance: vi.fn(), address: 'GBKLYONWFBQFBFZK6HMTXQZJNBKQEXZ3PJOVXNKZXVTV4FQXVMKLKHA' }),
3837
}));
3938

components/__tests__/StreamComparisonModal.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { describe, it, expect } from "vitest";
33
describe("Stream Comparison Feature", () => {
44
// Test 1: Verify the component exists and exports
55
it("should export StreamComparisonModal component", async () => {
6-
const module = await import("@/components/StreamComparisonModal");
7-
expect(module.default).toBeDefined();
6+
const mod = await import("@/components/StreamComparisonModal");
7+
expect(mod.default).toBeDefined();
88
});
99

1010
// Test 2: Verify stream detail imports are correct
1111
it("should have correct imports in stream detail page", async () => {
1212
// This is a simple validation that the file exists
13-
const streamDetailPath = "/workspaces/sorostream-app/src/app/stream/[id]/page.tsx";
13+
const streamDetailPath = `${process.cwd()}/src/app/stream/[id]/page.tsx`;
1414
const fs = await import("fs/promises");
1515
const content = await fs.readFile(streamDetailPath, "utf-8");
1616

@@ -51,7 +51,7 @@ describe("Stream Comparison Feature", () => {
5151
];
5252

5353
expectedKeys.forEach((key) => {
54-
expect(translations.stream_detail[key]).toBeDefined();
54+
expect((translations.stream_detail as Record<string, unknown>)[key]).toBeDefined();
5555
});
5656
});
5757
});

components/__tests__/WalletConnect.test.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,9 @@ describe('WalletConnect', () => {
125125
render(<WalletConnect />);
126126
const button = screen.getByRole('button', { name: /connect freighter wallet/i });
127127

128-
await act(async () => {
129-
fireEvent.click(button);
130-
});
128+
fireEvent.click(button);
131129

132-
expect(button).toBeDisabled();
130+
await waitFor(() => expect(button).toBeDisabled());
133131
});
134132

135133
it('shows connected address and disconnect button when context has an address', () => {

src/app/admin/page.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ import {
4343
type TreasuryBalance,
4444
type ContractState,
4545
getMockStreams,
46-
type TreasuryBalance,
4746
type StreamData,
4847
} from "@/src/lib/sorostream";
4948
import { useXlmPrice } from "@/src/lib/useXlmPrice";
@@ -346,7 +345,7 @@ export default function AdminPage() {
346345

347346
// Non-admin wallets are redirected away from /admin with an error message.
348347
useEffect(() => {
349-
if (address && ADMIN_WALLET && !isAdmin) {
348+
if (address && ADMIN_ADDRESSES.length > 0 && !isAdmin) {
350349
addToast("Access denied: this page is restricted to the protocol admin wallet.", "error");
351350
router.replace("/dashboard");
352351
}
@@ -480,7 +479,7 @@ export default function AdminPage() {
480479
}
481480

482481
// Non-admin wallets: render nothing while the redirect above takes effect.
483-
if (ADMIN_WALLET && !isAdmin) {
482+
if (ADMIN_ADDRESSES.length > 0 && !isAdmin) {
484483
return null;
485484
}
486485

@@ -509,7 +508,7 @@ export default function AdminPage() {
509508
role="note"
510509
className="mb-6 rounded-lg bg-yellow-900/30 border border-yellow-700 text-yellow-300 text-sm px-4 py-3"
511510
>
512-
<strong>NEXT_PUBLIC_ADMIN_WALLET</strong> is not configured. Admin
511+
<strong>NEXT_PUBLIC_ADMIN_ADDRESS</strong> is not configured. Admin
513512
controls will not appear until an admin address is set.
514513
</div>
515514
)}
@@ -575,7 +574,6 @@ export default function AdminPage() {
575574
<strong>NEXT_PUBLIC_ADMIN_ADDRESS</strong> is not configured. The
576575
Sweep Fees button will not appear until at least one admin address is set.
577576
</div>
578-
)}
579577

580578
{address && ADMIN_ADDRESSES.length > 0 && !isAdmin && (
581579
<div
@@ -585,6 +583,7 @@ export default function AdminPage() {
585583
Connected as <span className="font-mono text-gray-300">{address}</span>. Sweep
586584
controls are only available to the configured admin wallet addresses.
587585
</div>
586+
)}
588587
</section>
589588

590589
{/* Fee Rate configuration */}

src/app/dashboard/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { useKeyboardShortcuts, type ShortcutGroup } from "@/src/lib/useKeyboardS
1717
import { useBookmarks } from "@/src/context/BookmarksContext";
1818
import { useWallet } from "@/src/context/WalletContext";
1919
import ArchiveBanner from "@/components/ArchiveBanner";
20+
import { getAllTags, getTagMap } from "@/src/lib/streamTags";
2021
import PortfolioChart from "@/components/PortfolioChart";
2122
import StreamExpiryAlerts from "@/components/StreamExpiryAlerts";
2223
import PortfolioSummaryCard from "@/components/PortfolioSummaryCard";
@@ -196,7 +197,7 @@ function DashboardContent() {
196197
case "amount":
197198
return dir * (a.deposit - b.deposit);
198199
case "status": {
199-
const order = { Active: 0, Ended: 1, Cancelled: 2 };
200+
const order: Record<string, number> = { Active: 0, Ended: 1, Cancelled: 2, Paused: 3 };
200201
return dir * ((order[a.status] ?? 3) - (order[b.status] ?? 3));
201202
}
202203
default:
@@ -681,7 +682,7 @@ function DashboardContent() {
681682
</div>
682683
)}
683684
</StreamErrorBoundary>
684-
</div>{/* end My Streams tabpanel */}
685+
</div>
685686
)}{/* end activeTab conditional */}
686687
</div>
687688

src/app/stream/[id]/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import WithdrawConfirmModal from "@/components/WithdrawConfirmModal";
3939
import StartCountdownTimer from "@/components/StartCountdownTimer";
4040
import EmbedWidgetModal from "@/components/EmbedWidgetModal";
4141
import StreamComparisonModal from "@/components/StreamComparisonModal";
42+
import StreamTagEditor from "@/components/StreamTagEditor";
43+
import { getGiftMessage } from "@/components/GiftStreamModal";
4244
import { useSettings } from "@/src/context/SettingsContext";
4345
import { formatStellarAmount } from "@/src/lib/sorostream";
4446
import { useTranslations } from "@/src/lib/i18n";
@@ -1356,7 +1358,6 @@ export default function StreamDetail({ params }: { params: { id: string } }) {
13561358
</section>
13571359
</StreamErrorBoundary>
13581360
</div>
1359-
</div>
13601361

13611362
<StreamQrModal
13621363
open={showQrModal}

src/app/stream/new/page.tsx

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"use client";
2-
import { useState, useEffect, Suspense } from "react";
32
import { useState, useEffect, useRef, Suspense } from "react";
43
import { useRouter, useSearchParams } from "next/navigation";
54
import DurationPicker from "@/components/DurationPicker";
@@ -144,9 +143,6 @@ function NewStreamWizard() {
144143
if (!isNaN(num) && num > 0) return Math.round(num);
145144
}
146145
return draft?.duration ?? 0;
147-
if (!durationParam) return settings.defaultDurationSeconds;
148-
const num = parseFloat(durationParam);
149-
return !isNaN(num) && num > 0 ? Math.round(num) : settings.defaultDurationSeconds;
150146
})();
151147

152148
const [recipient, setRecipient] = useState(initialRecipient);
@@ -157,13 +153,7 @@ function NewStreamWizard() {
157153
const [selectedToken, setSelectedToken] = useState<string>(
158154
SUPPORTED_TOKENS.find((t) => t.symbol === defaultToken)?.symbol ?? SUPPORTED_TOKENS[0].symbol,
159155
);
160-
const [duration, setDuration] = useState(initialDuration);
161-
const [selectedToken, setSelectedToken] = useState<string>(
162-
draft?.selectedToken ?? SUPPORTED_TOKENS[0].symbol,
163-
);
164156
const [customTokenAddress, setCustomTokenAddress] = useState(draft?.customTokenAddress ?? "");
165-
const [selectedToken, setSelectedToken] = useState<string>(settings.defaultToken || SUPPORTED_TOKENS[0].symbol);
166-
const [customTokenAddress, setCustomTokenAddress] = useState("");
167157
const [customTokenError, setCustomTokenError] = useState("");
168158
const [loading, setLoading] = useState(false);
169159
const [errors, setErrors] = useState({ recipient: "", amount: "", duration: "", endDate: "", cliffDate: "", scheduledStart: "" });
@@ -200,14 +190,6 @@ function NewStreamWizard() {
200190
...overrides,
201191
});
202192
}
203-
const [endDate, setEndDate] = useState("");
204-
// Pre-fill cliff from preference (convert seconds offset to a future datetime-local string)
205-
const [cliffDate, setCliffDate] = useState(() => {
206-
if (!defaultCliffDuration || defaultCliffDuration <= 0) return "";
207-
const dt = new Date(Date.now() + defaultCliffDuration * 1000);
208-
// datetime-local format: "YYYY-MM-DDTHH:MM"
209-
return dt.toISOString().slice(0, 16);
210-
});
211193

212194
// Scheduling
213195
const [schedulingEnabled, setSchedulingEnabled] = useState(false);
@@ -233,13 +215,6 @@ function NewStreamWizard() {
233215
const [txFailedStage, setTxFailedStage] = useState<TxStage | undefined>(undefined);
234216
const [txError, setTxError] = useState<string | undefined>(undefined);
235217

236-
function handleTemplateSelect(
237-
seconds: number,
238-
suggestedAmount?: string,
239-
recipientOverride?: string,
240-
tokenOverride?: string,
241-
cliffDateOverride?: string,
242-
) {
243218
// Protocol fee state for review step
244219
const [feeBasisPoints, setFeeBasisPoints] = useState<number>(0);
245220
const [feeLoading, setFeeLoading] = useState(false);
@@ -412,7 +387,7 @@ function NewStreamWizard() {
412387
return () => { cancelled = true; };
413388
}, [step, address]);
414389

415-
function handleTemplateSelect(seconds: number, suggestedAmount?: string, recipientOverride?: string) {
390+
function handleTemplateSelect(seconds: number, suggestedAmount?: string, recipientOverride?: string, tokenOverride?: string, cliffDateOverride?: string) {
416391
setDuration(seconds);
417392
setErrors((prev) => ({ ...prev, duration: "" }));
418393
const newAmount = suggestedAmount ?? amount;
@@ -1198,7 +1173,7 @@ function NewStreamWizard() {
11981173
{step === "preview" && (
11991174
<div className="space-y-6">
12001175
<div className="bg-gray-800 rounded-xl p-6 space-y-4 border border-gray-700">
1201-
<p className="text-gray-400 text-sm mb-4">Here's what your stream will look like on-chain:</p>
1176+
<p className="text-gray-400 text-sm mb-4">Here&apos;s what your stream will look like on-chain:</p>
12021177

12031178
{/* Flow rate per day */}
12041179
<div>
@@ -1259,7 +1234,7 @@ function NewStreamWizard() {
12591234
{/* Info box */}
12601235
<div className="bg-blue-900/20 border border-blue-700/50 rounded-lg p-4">
12611236
<p className="text-blue-300 text-sm">
1262-
Review the details above. Click "Confirm" to proceed to sign this transaction with your wallet, or "Back" to edit the stream parameters.
1237+
Review the details above. Click &quot;Confirm&quot; to proceed to sign this transaction with your wallet, or &quot;Back&quot; to edit the stream parameters.
12631238
</p>
12641239
</div>
12651240
</div>

0 commit comments

Comments
 (0)