Skip to content

Commit

Permalink
feat(mobile): [Transaction] add select category field (#98)
Browse files Browse the repository at this point in the history
<img width="505" alt="Screenshot 2024-07-10 at 19 59 32" src="https://github.com/sixpm-ai/6pm/assets/16166195/c9f21ade-c13f-4e8d-b1c2-117b2b54264b">
  • Loading branch information
bkdev98 committed Jul 11, 2024
1 parent 42573b5 commit 5d551c6
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 8 deletions.
140 changes: 140 additions & 0 deletions apps/mobile/components/transaction/select-category-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { sleep } from '@/lib/utils'
import { useCategories } from '@/queries/category'
import type { Category } from '@6pm/validation'
import {
BottomSheetBackdrop,
BottomSheetModal,
BottomSheetSectionList,
} from '@gorhom/bottom-sheet'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { useRef } from 'react'
import { useController } from 'react-hook-form'
import { FlatList, Keyboard, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { FullWindowOverlay } from 'react-native-screens'
import GenericIcon from '../common/generic-icon'
import { Button } from '../ui/button'
import { Text } from '../ui/text'

export function SelectCategoryField({
onSelect,
}: {
onSelect?: (category: Category) => void
}) {
const { bottom } = useSafeAreaInsets()
const { data: categories = [], isLoading } = useCategories()

const sheetRef = useRef<BottomSheetModal>(null)
const { i18n } = useLingui()
const {
field: { onChange, onBlur, value },
} = useController({ name: 'categoryId' })

const selectedCategory = categories?.find((category) => category.id === value)

const incomeCategories = categories.filter(
(category) => category.type === 'INCOME',
)
const expenseCategories = categories.filter(
(category) => category.type === 'EXPENSE',
)

const sections = [
{ key: 'INCOME', title: 'Incomes', data: incomeCategories },
{ key: 'EXPENSE', title: 'Expenses', data: expenseCategories },
]

return (
<>
<Button
variant="secondary"
className="border border-border !px-3 max-w-[160px]"
disabled={isLoading}
onPress={() => {
Keyboard.dismiss()
sheetRef.current?.present()
}}
>
<GenericIcon
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
name={(selectedCategory?.icon as any) || 'Shapes'}
className="w-5 h-5 text-primary"
/>
<Text className="shrink line-clamp-1">
{selectedCategory?.name || t(i18n)`Uncategorized`}
</Text>
</Button>
<BottomSheetModal
ref={sheetRef}
index={0}
enableDynamicSizing
enablePanDownToClose
keyboardBehavior="extend"
backdropComponent={(props) => (
<BottomSheetBackdrop
{...props}
appearsOnIndex={0}
disappearsOnIndex={-1}
enableTouchThrough
/>
)}
containerComponent={(props) => (
<FullWindowOverlay>{props.children}</FullWindowOverlay>
)}
>
<BottomSheetSectionList
sections={sections}
keyExtractor={(i) => i.id}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
contentContainerClassName="px-2"
keyboardDismissMode="on-drag"
renderSectionHeader={({ section: { title } }) => (
<Text className="text-base bg-card font-medium text-center py-2">
{title}
</Text>
)}
contentContainerStyle={{ paddingBottom: bottom + 16 }}
renderItem={({ section, index }) =>
index === 0 ? (
<FlatList
data={section.data}
numColumns={4}
keyExtractor={(i) => i.id}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => (
<View className="p-1.5 w-[25%]">
<Button
size="icon"
className="h-20 flex flex-1 w-full gap-2 px-2 flex-col flex-grow"
variant={value === item ? 'secondary' : 'ghost'}
onPress={async () => {
sheetRef.current?.close()
await sleep(500)
onChange(item.id)
onBlur()
onSelect?.(item)
}}
>
<GenericIcon
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
name={item.icon as any}
className="size-8 text-foreground"
/>
<Text className="text-muted-foreground line-clamp-1 text-center !text-sm">
{item.name}
</Text>
</Button>
</View>
)}
/>
) : null
}
/>
</BottomSheetModal>
</>
)
}
11 changes: 3 additions & 8 deletions apps/mobile/components/transaction/transaction-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import { zodResolver } from '@hookform/resolvers/zod'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { Calendar, LandPlot, ShapesIcon, XIcon } from 'lucide-react-native'
import { Calendar, LandPlot, XIcon } from 'lucide-react-native'
import { Controller, FormProvider, useForm } from 'react-hook-form'
import { ScrollView, View } from 'react-native'
import Animated, {
Expand All @@ -19,6 +19,7 @@ import { TextTicker } from '../text-ticker'
import { Button } from '../ui/button'
import { Text } from '../ui/text'
import { SelectAccountField } from './select-account-field'
import { SelectCategoryField } from './select-category-field'

type TransactionFormProps = {
onSubmit: (data: TransactionFormValues) => void
Expand Down Expand Up @@ -105,13 +106,7 @@ export const TransactionForm = ({
)
}}
/>
<Button
variant="secondary"
className="border border-border !px-3"
>
<ShapesIcon className="w-5 h-5 text-primary" />
<Text>{t(i18n)`Uncategorized`}</Text>
</Button>
<SelectCategoryField />
</View>
<SubmitButton
onPress={transactionForm.handleSubmit(onSubmit)}
Expand Down

0 comments on commit 5d551c6

Please sign in to comment.