From 0e712f2e2f0cb82b9de96af05f4347382b677da7 Mon Sep 17 00:00:00 2001 From: Ken Yasue Date: Tue, 25 Mar 2025 13:55:43 +0100 Subject: [PATCH] Add customer list filters and total count display - Add search filters for customer name, email, and URL - Add filter for customers with email - Display total number of customers - Update API to handle filter parameters --- src/app/(admin)/admin/customers/page.tsx | 86 ++++++++++++++++++++++-- src/app/api/customers/route.ts | 26 ++++++- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/app/(admin)/admin/customers/page.tsx b/src/app/(admin)/admin/customers/page.tsx index 7abbad1..d570b25 100644 --- a/src/app/(admin)/admin/customers/page.tsx +++ b/src/app/(admin)/admin/customers/page.tsx @@ -39,6 +39,12 @@ export default function AdminCustomers() { const [page, setPage] = useState(initialPage); const [pageSize, setPageSize] = useState(initialPageSize); + // Search filters state + const [nameFilter, setNameFilter] = useState(''); + const [emailFilter, setEmailFilter] = useState(''); + const [urlFilter, setUrlFilter] = useState(''); + const [hasEmailFilter, setHasEmailFilter] = useState(false); + // State for data const [customers, setCustomers] = useState([]); const [pagination, setPagination] = useState({ @@ -57,11 +63,16 @@ export default function AdminCustomers() { setError(null); try { - // Build query string with pagination + // Build query string with pagination and filters const params = new URLSearchParams(); params.append('page', initialPage.toString()); params.append('pageSize', initialPageSize.toString()); + if (nameFilter) params.append('name', nameFilter); + if (emailFilter) params.append('email', emailFilter); + if (urlFilter) params.append('url', urlFilter); + if (hasEmailFilter) params.append('hasEmail', 'true'); + const response = await fetch(`/api/customers?${params.toString()}`); if (!response.ok) { @@ -80,7 +91,7 @@ export default function AdminCustomers() { }; fetchCustomers(); - }, [initialPage, initialPageSize]); + }, [initialPage, initialPageSize, nameFilter, emailFilter, urlFilter, hasEmailFilter]); // Handle page change const handlePageChange = (newPage: number) => { @@ -96,8 +107,15 @@ export default function AdminCustomers() { return (
-
-

Customers

+
+
+

Customers

+ {!isLoading && ( +

+ Total: {pagination.totalCount} customer{pagination.totalCount !== 1 ? 's' : ''} +

+ )} +
+ {/* Search Filters */} +
+
+ + setNameFilter(e.target.value)} + className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white sm:text-sm" + placeholder="Enter name..." + /> +
+
+ + setEmailFilter(e.target.value)} + className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white sm:text-sm" + placeholder="Enter email..." + /> +
+
+ + setUrlFilter(e.target.value)} + className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white sm:text-sm" + placeholder="Enter URL..." + /> +
+
+ +
+ setHasEmailFilter(e.target.checked)} + className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600" + /> + +
+
+
+ {/* Error Message */} {error && (
diff --git a/src/app/api/customers/route.ts b/src/app/api/customers/route.ts index 4af014b..c33eae3 100644 --- a/src/app/api/customers/route.ts +++ b/src/app/api/customers/route.ts @@ -15,9 +15,31 @@ export async function GET(request: NextRequest) { const pageSize = parseInt(url.searchParams.get('pageSize') || '10'); const skip = (page - 1) * pageSize; + // Get filter parameters + const nameFilter = url.searchParams.get('name'); + const emailFilter = url.searchParams.get('email'); + const urlFilter = url.searchParams.get('url'); + const hasEmailFilter = url.searchParams.get('hasEmail'); + // Build query - let queryBuilder = customerRepository.createQueryBuilder('customer') - .orderBy('customer.createdAt', 'DESC'); + let queryBuilder = customerRepository.createQueryBuilder('customer'); + + // Apply filters + if (nameFilter) { + queryBuilder = queryBuilder.andWhere('LOWER(customer.name) LIKE LOWER(:name)', { name: `%${nameFilter}%` }); + } + if (emailFilter) { + queryBuilder = queryBuilder.andWhere('LOWER(customer.email) LIKE LOWER(:email)', { email: `%${emailFilter}%` }); + } + if (urlFilter) { + queryBuilder = queryBuilder.andWhere('LOWER(customer.url) LIKE LOWER(:url)', { url: `%${urlFilter}%` }); + } + if (hasEmailFilter === 'true') { + queryBuilder = queryBuilder.andWhere('customer.email IS NOT NULL AND customer.email != :emptyString', { emptyString: '' }); + } + + // Add ordering + queryBuilder = queryBuilder.orderBy('customer.createdAt', 'DESC'); // Get total count for pagination const totalCount = await queryBuilder.getCount();