From ae7cb2ccc84cf25332d1efabeb197a5e1b05d029 Mon Sep 17 00:00:00 2001 From: Ankit Bahl Date: Fri, 19 Jan 2024 13:38:18 -0800 Subject: [PATCH] Added search bar for expense list page (#52) * Added search bar for expense list page * Change search input styling --------- Co-authored-by: Sebastien Castiel --- .../[groupId]/expenses/expense-list.tsx | 172 ++++++++++-------- src/components/ui/search-bar.tsx | 33 ++++ 2 files changed, 128 insertions(+), 77 deletions(-) create mode 100644 src/components/ui/search-bar.tsx diff --git a/src/app/groups/[groupId]/expenses/expense-list.tsx b/src/app/groups/[groupId]/expenses/expense-list.tsx index 73c8c6e..b083ab6 100644 --- a/src/app/groups/[groupId]/expenses/expense-list.tsx +++ b/src/app/groups/[groupId]/expenses/expense-list.tsx @@ -1,6 +1,7 @@ 'use client' import { CategoryIcon } from '@/app/groups/[groupId]/expenses/category-icon' import { Button } from '@/components/ui/button' +import { SearchBar } from '@/components/ui/search-bar' import { getGroupExpenses } from '@/lib/api' import { cn } from '@/lib/utils' import { Expense, Participant } from '@prisma/client' @@ -8,7 +9,7 @@ import dayjs, { type Dayjs } from 'dayjs' import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/navigation' -import { Fragment, useEffect } from 'react' +import { Fragment, useEffect, useState } from 'react' type Props = { expenses: Awaited> @@ -63,6 +64,7 @@ export function ExpenseList({ participants, groupId, }: Props) { + const [searchText, setSearchText] = useState('') useEffect(() => { const activeUser = localStorage.getItem('newGroup-activeUser') const newUser = localStorage.getItem(`${groupId}-newUser`) @@ -86,86 +88,102 @@ export function ExpenseList({ const router = useRouter() const groupedExpensesByDate = getGroupedExpensesByDate(expenses) - return expenses.length > 0 ? ( - Object.values(EXPENSE_GROUPS).map((expenseGroup: string) => { - const groupExpenses = groupedExpensesByDate[expenseGroup] - if (!groupExpenses) return null - return ( -
-
- {expenseGroup} -
- {groupExpenses.map((expense: any) => ( + <> + setSearchText(e.target.value)} /> + {Object.values(EXPENSE_GROUPS).map((expenseGroup: string) => { + const groupExpenses = groupedExpensesByDate[expenseGroup] + if (!groupExpenses) return null + return ( +
{ - router.push(`/groups/${groupId}/expenses/${expense.id}/edit`) - }} + className={ + 'text-muted-foreground text-xs pl-4 sm:pl-6 py-1 font-semibold sticky top-16 bg-white dark:bg-[#1b1917]' + } > - -
-
- {expense.title} -
-
- Paid by{' '} - {getParticipant(expense.paidById)?.name} for{' '} - {expense.paidFor.map((paidFor: any, index: number) => ( - - {index !== 0 && <>, } - - { - participants.find( - (p) => p.id === paidFor.participantId, - )?.name - } - - - ))} -
-
-
-
- {currency} {(expense.amount / 100).toFixed(2)} -
-
- {formatDate(expense.expenseDate)} -
-
- + {expenseGroup}
- ))} -
- ) - }) + {groupExpenses + .filter( + (exp) => + exp.title.toLowerCase().match(searchText.toLowerCase()) !== + null, + ) + .map((expense: any) => ( +
{ + router.push( + `/groups/${groupId}/expenses/${expense.id}/edit`, + ) + }} + > + +
+
+ {expense.title} +
+
+ Paid by{' '} + {getParticipant(expense.paidById)?.name}{' '} + for{' '} + {expense.paidFor.map((paidFor: any, index: number) => ( + + {index !== 0 && <>, } + + { + participants.find( + (p) => p.id === paidFor.participantId, + )?.name + } + + + ))} +
+
+
+
+ {currency} {(expense.amount / 100).toFixed(2)} +
+
+ {formatDate(expense.expenseDate)} +
+
+ +
+ ))} +
+ ) + })} + ) : (

Your group doesn’t contain any expense yet.{' '} diff --git a/src/components/ui/search-bar.tsx b/src/components/ui/search-bar.tsx new file mode 100644 index 0000000..6369c55 --- /dev/null +++ b/src/components/ui/search-bar.tsx @@ -0,0 +1,33 @@ +import * as React from "react" + +import {Input} from "@/components/ui/input"; +import {cn} from "@/lib/utils"; +import { + Search +} from 'lucide-react' + +export interface InputProps + extends React.InputHTMLAttributes {} + +const SearchBar = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( +

+ + +
+ ) + } +) +SearchBar.displayName = "SearchBar" + +export { SearchBar }