182 lines
7.6 KiB
Markdown
182 lines
7.6 KiB
Markdown
# Response Wall Bug Fixes
|
|
|
|
## Issues Identified and Fixed
|
|
|
|
### 1. **TypeError: responses.filter is not a function**
|
|
**Error Location**: `app/controllers/responses.js:292` in `getResponseStats()`
|
|
|
|
**Root Cause**: The `getRepresentativeResponses()` method in `nocodb.js` was returning the raw NocoDB API response object `{list: [...], pageInfo: {...}}` instead of an array. The controller code expected an array and tried to call `.filter()` on an object.
|
|
|
|
**Fix Applied**: Modified `getRepresentativeResponses()` to extract the `list` array from the response and normalize each item:
|
|
|
|
```javascript
|
|
async getRepresentativeResponses(params = {}) {
|
|
if (!this.tableIds.representativeResponses) {
|
|
throw new Error('Representative responses table not configured');
|
|
}
|
|
const result = await this.getAll(this.tableIds.representativeResponses, params);
|
|
// NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
|
|
const list = result.list || [];
|
|
return list.map(item => this.normalizeResponse(item));
|
|
}
|
|
```
|
|
|
|
### 2. **TypeError: responses.map is not a function**
|
|
**Error Location**: `app/controllers/responses.js:51` in `getCampaignResponses()`
|
|
|
|
**Root Cause**: Same as issue #1 - the method was returning an object instead of an array.
|
|
|
|
**Fix Applied**: Same fix as above ensures an array is always returned.
|
|
|
|
### 3. **Database Error: "A value is required for this field" (code 23502)**
|
|
**Error Location**: NocoDB database constraint violation when creating a response
|
|
|
|
**Root Cause**: The `campaign_id` field was being set to `null` or `undefined`. Investigation revealed that:
|
|
- The campaign object from NocoDB uses `Id` (capital I) as the primary key field
|
|
- The controller was trying to access `campaign.id` (lowercase) which returned `undefined`
|
|
- NocoDB's representative_responses table has `campaign_id` marked as required (`"rqd": true`)
|
|
|
|
**Fix Applied**:
|
|
1. Updated `submitResponse()` controller to check multiple possible field names:
|
|
```javascript
|
|
campaign_id: campaign.Id || campaign.id || campaign['Campaign ID'],
|
|
```
|
|
|
|
2. Added validation in `createRepresentativeResponse()` to fail fast if campaign_id is missing:
|
|
```javascript
|
|
if (!responseData.campaign_id) {
|
|
throw new Error('Campaign ID is required for creating a response');
|
|
}
|
|
```
|
|
|
|
3. Added debug logging to track the campaign_id value:
|
|
```javascript
|
|
console.log('Submitting response with campaign_id:', newResponse.campaign_id, 'from campaign:', campaign);
|
|
```
|
|
|
|
### 4. **Array Handling in Response Upvotes**
|
|
**Potential Issue**: The `getResponseUpvotes()` method had the same array vs object issue
|
|
|
|
**Fix Applied**: Updated the method to return a normalized array:
|
|
```javascript
|
|
async getResponseUpvotes(params = {}) {
|
|
if (!this.tableIds.responseUpvotes) {
|
|
throw new Error('Response upvotes table not configured');
|
|
}
|
|
const result = await this.getAll(this.tableIds.responseUpvotes, params);
|
|
// NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
|
|
const list = result.list || [];
|
|
return list.map(item => this.normalizeUpvote(item));
|
|
}
|
|
```
|
|
|
|
## Files Modified
|
|
|
|
1. **app/services/nocodb.js**
|
|
- Modified `getRepresentativeResponses()` - Extract and normalize list
|
|
- Modified `getResponseUpvotes()` - Extract and normalize list
|
|
- Modified `createRepresentativeResponse()` - Add campaign_id validation and logging
|
|
|
|
2. **app/controllers/responses.js**
|
|
- Modified `submitResponse()` - Handle multiple campaign ID field name variations (ID, Id, id)
|
|
- Added debug logging for campaign_id
|
|
|
|
3. **app/public/js/admin.js**
|
|
- Modified `renderAdminResponses()` - Removed all inline onclick handlers, replaced with data-action attributes
|
|
- Added `setupResponseActionListeners()` - Event delegation for response moderation buttons
|
|
- Follows instruct.md guidelines: "No inline event handlers. Always use addEventListener in JS files."
|
|
|
|
4. **app/public/js/api-client.js**
|
|
- Added `put()` method for HTTP PUT requests
|
|
- Added `patch()` method for HTTP PATCH requests
|
|
- Added `delete()` method for HTTP DELETE requests
|
|
- These methods were missing and causing errors in admin panel operations
|
|
|
|
## Testing
|
|
|
|
After applying these fixes, test the following:
|
|
|
|
1. **Load Response Wall** - Visit `http://localhost:3333/response-wall.html?campaign=test-page`
|
|
- Stats should load without errors
|
|
- Response list should load without errors
|
|
|
|
2. **Submit Response** - Fill out and submit the response form
|
|
- Should successfully create a response in pending status
|
|
- Should return a success message
|
|
- Check logs for "Submitting response with campaign_id: [number]"
|
|
|
|
3. **Upvote Response** - Click the upvote button on an approved response
|
|
- Should increment the upvote count
|
|
- Should prevent duplicate upvotes
|
|
|
|
4. **Admin Moderation** - Visit `http://localhost:3333/admin.html` → Response Moderation tab
|
|
- Should see pending responses
|
|
- Should be able to approve/reject responses
|
|
|
|
## Deployment
|
|
|
|
The application container has been restarted with:
|
|
```bash
|
|
docker compose restart app
|
|
```
|
|
|
|
All fixes are now live and ready for testing.
|
|
|
|
## Root Cause Analysis
|
|
|
|
The main issue was a misunderstanding of NocoDB's API response structure:
|
|
- **Expected**: Array of records directly
|
|
- **Actual**: Object with `{list: [records], pageInfo: {...}}`
|
|
|
|
This is a common pattern in REST APIs for pagination support. The fix ensures all service methods return properly normalized arrays for consistent usage throughout the application.
|
|
|
|
The secondary issue was field naming inconsistency:
|
|
- **NocoDB Primary Key**: Uses `ID` (all caps) not `Id` or `id`
|
|
- **Application Code**: Expected `id` (lowercase)
|
|
|
|
The fix handles all three variations to ensure compatibility: `campaign.ID || campaign.Id || campaign.id`
|
|
|
|
### 5. **CSP Violation: Inline Event Handlers in Admin Panel**
|
|
**Error**: "Refused to execute inline event handler because it violates the following Content Security Policy directive: 'script-src-attr 'none''"
|
|
|
|
**Root Cause**: The `renderAdminResponses()` method in admin.js was using inline `onclick` handlers like:
|
|
```javascript
|
|
<button onclick="adminPanel.approveResponse(${response.id})">
|
|
```
|
|
|
|
This violates the development guidelines in instruct.md which explicitly state: **"No inline event handlers. Always use addEventListener in JS files."**
|
|
|
|
**Fix Applied**:
|
|
- Replaced all inline onclick handlers with data-action attributes
|
|
- Created `setupResponseActionListeners()` method using event delegation
|
|
- All buttons now use pattern: `data-action="approve-response" data-response-id="${response.id}"`
|
|
- Event delegation listens on container and routes actions based on data attributes
|
|
|
|
### 6. **Missing HTTP Methods in API Client**
|
|
**Error**: "TypeError: window.apiClient.patch is not a function"
|
|
|
|
**Root Cause**: The APIClient class in api-client.js only had `get()` and `post()` methods. Admin panel operations needed `patch()`, `put()`, and `delete()` methods for updating and deleting responses.
|
|
|
|
**Fix Applied**: Added three new methods to APIClient:
|
|
```javascript
|
|
async put(endpoint, data) { ... }
|
|
async patch(endpoint, data) { ... }
|
|
async delete(endpoint) { ... }
|
|
```
|
|
|
|
## Prevention
|
|
|
|
To prevent similar issues in the future:
|
|
|
|
1. **Type Safety**: Consider adding TypeScript or JSDoc type annotations
|
|
2. **Consistent Normalization**: Always normalize data at the service layer
|
|
3. **Field Name Standards**: Document NocoDB field naming conventions
|
|
4. **Validation**: Add validation for required fields early in the request flow
|
|
5. **Logging**: Continue adding debug logging for data transformations
|
|
|
|
## Related Documentation
|
|
|
|
- See `RESPONSE_WALL_USAGE.md` for usage instructions
|
|
- See `RESPONSE_WALL_IMPLEMENTATION.md` for feature implementation details
|
|
- See `scripts/build-nocodb.sh` for database schema definitions
|