From 6ce44a713da9e903a1f1be817d2348c5b84216a1 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 15 Nov 2025 00:10:57 +0000 Subject: [PATCH 1/4] Initial commit with task details for issue #56 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/xierongchuan/TaskMateFrontend/issues/56 --- CLAUDE.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 4d47fc9..a711ae8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -154,3 +154,15 @@ The application supports multi-tenancy through dealership-based data filtering. - Error messages are user-friendly and localized - Component styling follows Tailwind CSS patterns with consistent design tokens - Form validation includes both client-side and server-side error handling + +--- + +Issue to solve: https://github.com/xierongchuan/TaskMateFrontend/issues/56 +Your prepared branch: issue-56-12a233a14969 +Your prepared working directory: /tmp/gh-issue-solver-1763165450540 +Your forked repository: konard/TaskMateFrontend +Original repository (upstream): xierongchuan/TaskMateFrontend + +Proceed. + +Run timestamp: 2025-11-15T00:10:56.961Z \ No newline at end of file From e08593c3af520dd89463fd2a3f73410caa7bd564 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 15 Nov 2025 00:16:37 +0000 Subject: [PATCH 2/4] fix(tasks): clean filter parameters before API request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #56 Problem: - When selecting dealerships in the Tasks page filter, the first selection sent incorrect request parameters to the server, while the second selection worked correctly. - Root cause: Empty strings, null values, and empty arrays from the filters object were being sent as query parameters (e.g., ?search=&status=&recurrence=) - The backend was interpreting these empty parameters incorrectly. Solution: - Implemented filter cleaning logic in the queryFn before sending the API request - Removes null, undefined, empty strings, and empty arrays from filter parameters - Only sends non-empty filter values to the server - This ensures consistent behavior regardless of which dealership is selected first Testing: - Verified TypeScript compilation passes - Verified ESLint passes for modified file - Added experiment script to demonstrate the issue and solution 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- experiments/test-axios-params.js | 91 ++++++++++++++++++++++++++++++++ src/pages/TasksPage.tsx | 31 +++++++++-- 2 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 experiments/test-axios-params.js diff --git a/experiments/test-axios-params.js b/experiments/test-axios-params.js new file mode 100644 index 0000000..01a9148 --- /dev/null +++ b/experiments/test-axios-params.js @@ -0,0 +1,91 @@ +// Test script to understand how axios handles empty parameters + +// Simulate the filters object from TasksPage +const filters = { + search: '', + status: '', + recurrence: '', + task_type: '', + response_type: '', + date_range: 'all', + dealership_id: null, + tags: [], +}; + +// Simulate what happens when first dealership is selected (id: 1) +const filtersWithFirstDealership = { + ...filters, + dealership_id: 1, +}; + +// Simulate what happens when dealership_id || undefined is used +const filtersWithUndefined = { + ...filters, + dealership_id: filters.dealership_id || undefined, +}; + +console.log('=== Original filters ==='); +console.log(JSON.stringify(filters, null, 2)); + +console.log('\n=== Filters with first dealership (id: 1) ==='); +console.log(JSON.stringify(filtersWithFirstDealership, null, 2)); + +console.log('\n=== Filters with dealership_id || undefined ==='); +console.log(JSON.stringify(filtersWithUndefined, null, 2)); + +// Create a mock request to see what URL would be generated +const testUrl = 'http://localhost:8000/api/v1/tasks'; + +console.log('\n=== Testing URL generation ==='); + +// Test with axios URLSearchParams +const params1 = new URLSearchParams(); +Object.entries(filters).forEach(([key, value]) => { + if (value !== null && value !== undefined && value !== '') { + if (Array.isArray(value)) { + value.forEach(v => params1.append(key, v)); + } else { + params1.append(key, value.toString()); + } + } +}); + +console.log('URL with filtered params:', `${testUrl}?${params1.toString()}`); + +// Test with all params (including empty) +const params2 = new URLSearchParams(); +Object.entries(filtersWithFirstDealership).forEach(([key, value]) => { + if (value !== null && value !== undefined) { + if (Array.isArray(value)) { + if (value.length > 0) { + value.forEach(v => params2.append(key, v)); + } + } else { + params2.append(key, value.toString()); + } + } +}); + +console.log('URL with dealership_id=1 (filtered):', `${testUrl}?${params2.toString()}`); + +// Test what axios actually sends +console.log('\n=== What axios would send (raw params) ==='); +console.log('With empty strings:', filtersWithFirstDealership); + +// Helper function to clean params +function cleanParams(params) { + const cleaned = {}; + Object.entries(params).forEach(([key, value]) => { + if (value !== null && value !== undefined && value !== '') { + if (Array.isArray(value) && value.length > 0) { + cleaned[key] = value; + } else if (!Array.isArray(value)) { + cleaned[key] = value; + } + } + }); + return cleaned; +} + +console.log('\n=== Cleaned params ==='); +console.log('Cleaned filters:', cleanParams(filtersWithFirstDealership)); diff --git a/src/pages/TasksPage.tsx b/src/pages/TasksPage.tsx index dd48983..301804d 100644 --- a/src/pages/TasksPage.tsx +++ b/src/pages/TasksPage.tsx @@ -44,10 +44,33 @@ export const TasksPage: React.FC = () => { const { data: tasksData, isLoading, error } = useQuery({ queryKey: ['tasks', filters], - queryFn: () => tasksApi.getTasks({ - ...filters, - dealership_id: filters.dealership_id || undefined, - }), + queryFn: () => { + // Clean filters: remove empty strings, null values, and empty arrays + const cleanedFilters: { + search?: string; + status?: string; + recurrence?: string; + task_type?: string; + response_type?: string; + date_range?: string; + dealership_id?: number; + tags?: string[]; + } = {}; + + Object.entries(filters).forEach(([key, value]) => { + if (value !== null && value !== undefined && value !== '') { + if (Array.isArray(value)) { + if (value.length > 0) { + cleanedFilters[key as keyof typeof cleanedFilters] = value as never; + } + } else { + cleanedFilters[key as keyof typeof cleanedFilters] = value as never; + } + } + }); + + return tasksApi.getTasks(cleanedFilters); + }, refetchInterval: 30000, }); From 4358dc129fda53513bdc306ab3c61d8280f30a4b Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 15 Nov 2025 00:17:49 +0000 Subject: [PATCH 3/4] docs: clean up CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove temporary task details that were added during issue setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- CLAUDE.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a711ae8..d8a31a2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -153,16 +153,4 @@ The application supports multi-tenancy through dealership-based data filtering. - All date formatting uses Russian locale (`ru`) - Error messages are user-friendly and localized - Component styling follows Tailwind CSS patterns with consistent design tokens -- Form validation includes both client-side and server-side error handling - ---- - -Issue to solve: https://github.com/xierongchuan/TaskMateFrontend/issues/56 -Your prepared branch: issue-56-12a233a14969 -Your prepared working directory: /tmp/gh-issue-solver-1763165450540 -Your forked repository: konard/TaskMateFrontend -Original repository (upstream): xierongchuan/TaskMateFrontend - -Proceed. - -Run timestamp: 2025-11-15T00:10:56.961Z \ No newline at end of file +- Form validation includes both client-side and server-side error handling \ No newline at end of file From 42a3ca7bc0c6578ef877360fa99871f74fe496b2 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 15 Nov 2025 00:18:40 +0000 Subject: [PATCH 4/4] Revert: Remove CLAUDE.md changes from initial commit --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index d8a31a2..4d47fc9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -153,4 +153,4 @@ The application supports multi-tenancy through dealership-based data filtering. - All date formatting uses Russian locale (`ru`) - Error messages are user-friendly and localized - Component styling follows Tailwind CSS patterns with consistent design tokens -- Form validation includes both client-side and server-side error handling \ No newline at end of file +- Form validation includes both client-side and server-side error handling