Fix critical issues to ensure platform stability and user functionality
Addresses critical issues including SSR crashes due to improper localStorage/document access and a broken betting feature in Article.tsx. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aabe2db1-f078-4501-aab5-be145ebc6b9a Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/aabe2db1-f078-4501-aab5-be145ebc6b9a/TqVS1Ec
This commit is contained in:
365
frontend-issues.md
Normal file
365
frontend-issues.md
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
# Frontend Issues - Code Review Report
|
||||||
|
|
||||||
|
## 🔴 Critical Issues (Immediate Fix Required)
|
||||||
|
|
||||||
|
### 1. localStorage Access Without Browser Check - SSR Crash Risk
|
||||||
|
**Severity:** CRITICAL
|
||||||
|
**Files Affected:**
|
||||||
|
- `client/src/pages/Home.tsx`
|
||||||
|
- `client/src/pages/Landing.tsx`
|
||||||
|
- `client/src/pages/Auctions.tsx`
|
||||||
|
- `client/src/pages/MediaOutlet.tsx`
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Multiple pages initialize React state directly from `localStorage` without checking if `window` is defined:
|
||||||
|
```typescript
|
||||||
|
const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- **ReferenceError in SSR/non-browser environments** (tests, server-side rendering)
|
||||||
|
- Application crashes immediately on page load
|
||||||
|
- Breaks testing infrastructure
|
||||||
|
- Prevents server-side rendering if needed in future
|
||||||
|
|
||||||
|
**Reproduction:**
|
||||||
|
1. Run unit tests that mount these components
|
||||||
|
2. Try server-side rendering
|
||||||
|
3. Access `localStorage` before window is available
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
// ❌ Current (BROKEN)
|
||||||
|
const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light');
|
||||||
|
|
||||||
|
// ✅ Fixed
|
||||||
|
const [theme, setTheme] = useState(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('theme') || 'light';
|
||||||
|
}
|
||||||
|
return 'light';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alternative: Move to useEffect
|
||||||
|
const [theme, setTheme] = useState('light');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
if (savedTheme) setTheme(savedTheme);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P0 - Fix immediately
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Betting Feature Completely Broken - Ignores User Input
|
||||||
|
**Severity:** CRITICAL
|
||||||
|
**File:** `client/src/pages/Article.tsx`
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
The `handlePlaceBet` function ignores user input and always submits hardcoded value:
|
||||||
|
```typescript
|
||||||
|
const handlePlaceBet = (marketId: string, option: "yes" | "no") => {
|
||||||
|
// User input stored in betAmounts[marketId] is IGNORED
|
||||||
|
const amount = 10000; // ❌ HARDCODED!
|
||||||
|
|
||||||
|
placeBetMutation.mutate({ marketId, option, amount });
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Users cannot place custom bets
|
||||||
|
- All bets are forced to 10,000 regardless of input
|
||||||
|
- Primary feature of the page is non-functional
|
||||||
|
- Poor user experience
|
||||||
|
|
||||||
|
**Reproduction:**
|
||||||
|
1. Navigate to an article with prediction market
|
||||||
|
2. Enter any bet amount (e.g., 500)
|
||||||
|
3. Click place bet
|
||||||
|
4. Backend receives 10,000 instead of 500
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
// ❌ Current (BROKEN)
|
||||||
|
const handlePlaceBet = (marketId: string, option: "yes" | "no") => {
|
||||||
|
const amount = 10000; // Hardcoded!
|
||||||
|
placeBetMutation.mutate({ marketId, option, amount });
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ Fixed
|
||||||
|
const handlePlaceBet = (marketId: string, option: "yes" | "no") => {
|
||||||
|
const inputAmount = betAmounts[marketId];
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (!inputAmount || parseFloat(inputAmount) <= 0) {
|
||||||
|
toast({
|
||||||
|
title: "Invalid Amount",
|
||||||
|
description: "Please enter a valid bet amount greater than 0",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const amount = parseFloat(inputAmount);
|
||||||
|
placeBetMutation.mutate({ marketId, option, amount });
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P0 - Fix immediately
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟠 High Priority Issues
|
||||||
|
|
||||||
|
### 3. document.documentElement Access Without Browser Check
|
||||||
|
**Severity:** HIGH
|
||||||
|
**Files Affected:**
|
||||||
|
- `client/src/pages/Home.tsx`
|
||||||
|
- `client/src/pages/Landing.tsx`
|
||||||
|
- `client/src/pages/Auctions.tsx`
|
||||||
|
- `client/src/pages/MediaOutlet.tsx`
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Direct access to `document.documentElement` in useEffect without browser check:
|
||||||
|
```typescript
|
||||||
|
useEffect(() => {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark'); // No browser check!
|
||||||
|
}
|
||||||
|
}, [theme]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Crashes in SSR environments
|
||||||
|
- Breaks in test environments without DOM
|
||||||
|
- Prevents future SSR implementation
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
}
|
||||||
|
localStorage.setItem('theme', theme);
|
||||||
|
}, [theme]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P1 - Fix soon
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Missing Error State Rendering
|
||||||
|
**Severity:** HIGH
|
||||||
|
**Files Affected:**
|
||||||
|
- `client/src/pages/Auctions.tsx`
|
||||||
|
- `client/src/pages/MediaOutlet.tsx`
|
||||||
|
- `client/src/pages/Article.tsx`
|
||||||
|
- `client/src/pages/AdminDashboard.tsx`
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Queries fetch data but don't handle error states:
|
||||||
|
```typescript
|
||||||
|
const { data: auctions = [], isLoading } = useQuery<Auction[]>({
|
||||||
|
queryKey: ["/api/auctions"],
|
||||||
|
});
|
||||||
|
// No error handling! 😱
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Users see blank screen on API failures
|
||||||
|
- No feedback when network is down
|
||||||
|
- Poor user experience
|
||||||
|
- Difficult debugging
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
const { data: auctions = [], isLoading, error, isError } = useQuery<Auction[]>({
|
||||||
|
queryKey: ["/api/auctions"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add error rendering
|
||||||
|
if (isError) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-[400px] p-8">
|
||||||
|
<AlertCircle className="h-12 w-12 text-destructive mb-4" />
|
||||||
|
<h3 className="text-xl font-semibold mb-2">Failed to Load Auctions</h3>
|
||||||
|
<p className="text-muted-foreground mb-4">
|
||||||
|
{error?.message || "An error occurred while fetching data"}
|
||||||
|
</p>
|
||||||
|
<Button onClick={() => queryClient.invalidateQueries({ queryKey: ["/api/auctions"] })}>
|
||||||
|
Try Again
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P1 - Add error boundaries
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟡 Medium Priority Issues
|
||||||
|
|
||||||
|
### 5. Potential Memory Leak - Missing Cleanup in Mutations
|
||||||
|
**Severity:** MEDIUM
|
||||||
|
**Files Affected:** Multiple pages with mutations
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Mutations don't cancel on component unmount:
|
||||||
|
```typescript
|
||||||
|
const placeBetMutation = useMutation({
|
||||||
|
mutationFn: async (data) => { /* ... */ },
|
||||||
|
onSuccess: () => { /* ... */ }
|
||||||
|
});
|
||||||
|
// No cleanup when component unmounts!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- State updates after unmount warnings
|
||||||
|
- Memory leaks in SPA navigation
|
||||||
|
- React warnings in console
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
// Use React Query's built-in cleanup or add manual abort
|
||||||
|
const placeBetMutation = useMutation({
|
||||||
|
mutationFn: async (data, { signal }) => {
|
||||||
|
return await apiRequest("POST", `/api/endpoint`, data, { signal });
|
||||||
|
},
|
||||||
|
// React Query handles cleanup automatically
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P2 - Improve stability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. Form Validation Missing on Frontend
|
||||||
|
**Severity:** MEDIUM
|
||||||
|
**Files Affected:**
|
||||||
|
- `client/src/pages/Auctions.tsx` (bid form)
|
||||||
|
- `client/src/pages/Article.tsx` (bet form)
|
||||||
|
- `client/src/components/LoginModal.tsx`
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Forms rely only on backend validation:
|
||||||
|
```typescript
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={bidForm.amount}
|
||||||
|
onChange={(e) => setBidForm(prev => ({ ...prev, amount: e.target.value }))}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Poor UX - errors shown only after submission
|
||||||
|
- Unnecessary API calls with invalid data
|
||||||
|
- Backend load from validation
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
```typescript
|
||||||
|
// Add react-hook-form with zod validation
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const bidSchema = z.object({
|
||||||
|
amount: z.number()
|
||||||
|
.min(0.01, "Amount must be greater than 0")
|
||||||
|
.max(1000000, "Amount too large"),
|
||||||
|
qualityScore: z.number()
|
||||||
|
.int("Must be a whole number")
|
||||||
|
.min(1, "Score must be at least 1")
|
||||||
|
.max(100, "Score cannot exceed 100")
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
resolver: zodResolver(bidSchema),
|
||||||
|
defaultValues: { amount: "", qualityScore: "" }
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Priority:** P2 - Enhance UX
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟢 Low Priority Issues
|
||||||
|
|
||||||
|
### 7. Inconsistent Loading States
|
||||||
|
**Severity:** LOW
|
||||||
|
**Files Affected:** Multiple pages
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Some pages show skeleton loaders, others show nothing:
|
||||||
|
```typescript
|
||||||
|
{isLoading ? (
|
||||||
|
<div>Loading...</div> // Inconsistent!
|
||||||
|
) : (
|
||||||
|
<Content />
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- Inconsistent user experience
|
||||||
|
- Some pages feel slower than others
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
Create reusable skeleton components and use consistently.
|
||||||
|
|
||||||
|
**Priority:** P3 - Polish
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. Accessibility Issues
|
||||||
|
**Severity:** LOW
|
||||||
|
**Files Affected:** Multiple components
|
||||||
|
|
||||||
|
**Issues Found:**
|
||||||
|
- Missing ARIA labels on icon buttons
|
||||||
|
- Color contrast issues in dark mode
|
||||||
|
- Keyboard navigation not fully tested
|
||||||
|
- Focus management in modals could be improved
|
||||||
|
|
||||||
|
**Fix Solution:**
|
||||||
|
- Add aria-label to icon-only buttons
|
||||||
|
- Test with screen readers
|
||||||
|
- Implement focus traps in modals
|
||||||
|
- Add skip navigation links
|
||||||
|
|
||||||
|
**Priority:** P3 - Accessibility enhancement
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Severity | Count | Must Fix Before Production |
|
||||||
|
|----------|-------|----------------------------|
|
||||||
|
| 🔴 Critical | 2 | ✅ Yes |
|
||||||
|
| 🟠 High | 2 | ✅ Yes |
|
||||||
|
| 🟡 Medium | 2 | ⚠️ Recommended |
|
||||||
|
| 🟢 Low | 2 | ❌ Nice to have |
|
||||||
|
|
||||||
|
**Total Issues:** 8
|
||||||
|
|
||||||
|
**Estimated Fix Time:**
|
||||||
|
- Critical issues: 2-4 hours
|
||||||
|
- High priority: 4-6 hours
|
||||||
|
- Medium priority: 4-8 hours
|
||||||
|
- Low priority: 8-12 hours
|
||||||
|
|
||||||
|
**Recommended Fix Order:**
|
||||||
|
1. Fix localStorage/document browser checks (affects all environments)
|
||||||
|
2. Fix betting input bug (core functionality)
|
||||||
|
3. Add error state rendering (user experience)
|
||||||
|
4. Add form validation (UX improvement)
|
||||||
|
5. Address memory leaks (stability)
|
||||||
|
6. Polish loading states and accessibility (enhancement)
|
||||||
Reference in New Issue
Block a user