Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(mobile): config team owner for eas build #107

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/api/v1/routes/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ const router = new Hono()
z.object({
wallet_id: z.string().optional(),
budget_id: z.string().optional(),
before: z.date().optional(),
after: z.date().optional(),
first: z.number().optional(),
last: z.number().optional(),
before: z.date({ coerce: true }).optional(),
after: z.date({ coerce: true }).optional(),
first: z.number({ coerce: true }).optional(),
last: z.number({ coerce: true }).optional(),
}),
),
async (c) => {
Expand Down
11 changes: 7 additions & 4 deletions apps/api/v1/services/transaction.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export async function listTransactions({
const transactions = await prisma.transaction.findMany({
where: {
...query,
createdAt: {
date: {
...(pagination.before && {
lt: pagination.before,
}),
Expand All @@ -180,9 +180,12 @@ export async function listTransactions({
},
},
orderBy: {
createdAt: 'desc',
date: 'desc',
},
take: pagination.first || pagination.last,
include: {
category: true,
},
})

const totalCount = await prisma.transaction.count({
Expand All @@ -193,10 +196,10 @@ export async function listTransactions({
hasMore: transactions.length > (pagination.first || pagination.last || 0),
totalCount,
...(pagination.first && {
before: transactions[0]?.createdAt,
before: transactions[0]?.date,
}),
...(pagination.last && {
after: transactions[transactions.length - 1]?.createdAt,
after: transactions[transactions.length - 1]?.date,
}),
}

Expand Down
7 changes: 3 additions & 4 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router"
],
"plugins": ["expo-router"],
"experiments": {
"typedRoutes": true
},
Expand All @@ -43,6 +41,7 @@
"eas": {
"projectId": "5853e031-3bfb-41fe-bfb6-c49f746c4adc"
}
}
},
"owner": "sixpm"
}
}
108 changes: 103 additions & 5 deletions apps/mobile/app/(app)/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,114 @@
import { ListSkeleton } from '@/components/common/list-skeleton'
import { Toolbar } from '@/components/common/toolbar'
import { HomeHeader } from '@/components/home/header'
import { ScrollView, Text, View } from 'react-native'
import { WalletStatistics } from '@/components/home/wallet-statistics'
import { HandyArrow } from '@/components/transaction/handy-arrow'
import { TransactionItem } from '@/components/transaction/transaction-item'
import { Text } from '@/components/ui/text'
import { useColorScheme } from '@/hooks/useColorScheme'
import { formatDateShort } from '@/lib/date'
import { theme } from '@/lib/theme'
import { useTransactions } from '@/queries/transaction'
import type { TransactionPopulated } from '@6pm/validation'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { format } from 'date-fns/format'
import { LinearGradient } from 'expo-linear-gradient'
import { useMemo } from 'react'
import { SectionList, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'

const TRANSACTIONS_PER_PAGE = 15

export default function HomeScreen() {
const { top } = useSafeAreaInsets()
const { i18n } = useLingui()
const { top, bottom } = useSafeAreaInsets()
const {
data,
isLoading,
isRefetching,
refetch,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useTransactions({
last: TRANSACTIONS_PER_PAGE,
})
const { colorScheme } = useColorScheme()

const transactions =
data?.pages?.reduce((acc, page) => {
return acc.concat(page.transactions)
}, [] as TransactionPopulated[]) ?? []

const transactionsGroupByDate = useMemo(() => {
const groupedTransactions = transactions.reduce(
(acc, transaction) => {
const key = format(transaction.date, 'yyyy-MM-dd')
if (!acc[key]) {
acc[key] = []
}
acc[key].push(transaction)
return acc
},
{} as Record<string, TransactionPopulated[]>,
)
return Object.entries(groupedTransactions)
.map(([key, data]) => ({
key,
title: formatDateShort(new Date(key)),
data,
}))
.sort((a, b) => b.key.localeCompare(a.key))
}, [transactions])

return (
<View className="flex-1 bg-card" style={{ paddingTop: top }}>
<HomeHeader />
<ScrollView>
<Text className="font-sans">Home Screen</Text>
</ScrollView>
<SectionList
ListHeaderComponent={
<View className="p-6">
<WalletStatistics />
</View>
}
className="flex-1 bg-card"
contentContainerStyle={{ paddingBottom: bottom + 32 }}
refreshing={isRefetching}
onRefresh={refetch}
sections={transactionsGroupByDate}
keyExtractor={(item) => item.id}
renderItem={({ item: transaction }) => (
<TransactionItem transaction={transaction} />
)}
renderSectionHeader={({ section: { title } }) => (
<Text className="text-muted-foreground mx-6 bg-card py-2">
{title}
</Text>
)}
onEndReached={() => {
if (hasNextPage) {
fetchNextPage()
}
}}
onEndReachedThreshold={0.5}
ListFooterComponent={
isLoading || isFetchingNextPage ? <ListSkeleton /> : null
}
/>
{!transactions.length && !isLoading && (
<View className="absolute bottom-20 flex-row right-6 z-50 gap-3">
<Text>{t(i18n)`Add your first transaction here`}</Text>
<HandyArrow className="mt-4 text-muted-foreground" />
</View>
)}
<LinearGradient
colors={[
colorScheme === 'dark' ? 'transparent' : '#ffffff00',
theme[colorScheme ?? 'light'].background,
]}
className="absolute bottom-0 left-0 right-0 h-36"
pointerEvents="none"
/>
<Toolbar />
</View>
)
Expand Down
16 changes: 10 additions & 6 deletions apps/mobile/app/(app)/new-record.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { toast } from '@/components/common/toast'
import { TransactionForm } from '@/components/transaction/transaction-form'
import { createTransaction } from '@/mutations/transaction'
import { useWallets } from '@/queries/wallet'
import { transactionQueries } from '@/queries/transaction'
import { useWallets, walletQueries } from '@/queries/wallet'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { useMutation } from '@tanstack/react-query'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useRouter } from 'expo-router'
import { LoaderIcon } from 'lucide-react-native'
import { Alert, View } from 'react-native'
Expand All @@ -13,7 +14,7 @@ export default function NewRecordScreen() {
const router = useRouter()
const { data: walletAccounts } = useWallets()
const { i18n } = useLingui()
// const queryClient = useQueryClient()
const queryClient = useQueryClient()
const { mutateAsync } = useMutation({
mutationFn: createTransaction,
onError(error) {
Expand All @@ -24,9 +25,12 @@ export default function NewRecordScreen() {
toast.success(t(i18n)`Transaction created`)
},
async onSettled() {
// await queryClient.invalidateQueries({
// queryKey: transactionQueries.list._def,
// })
await queryClient.invalidateQueries({
queryKey: transactionQueries.all,
})
await queryClient.invalidateQueries({
queryKey: walletQueries.list._def,
})
},
})

Expand Down
6 changes: 6 additions & 0 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
ThemeProvider,
} from '@react-navigation/native'
import { QueryClientProvider } from '@tanstack/react-query'
import { LinearGradient } from 'expo-linear-gradient'
import { cssInterop } from 'nativewind'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
Expand All @@ -37,6 +38,11 @@ cssInterop(Svg, {
nativeStyleToProp: { width: true, height: true },
},
})
cssInterop(LinearGradient, {
className: {
target: 'style',
},
})

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync()
Expand Down
21 changes: 21 additions & 0 deletions apps/mobile/components/common/list-skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { View } from 'react-native'
import { Skeleton } from '../ui/skeleton'

export function ListSkeleton() {
return (
<>
<View className="flex-row items-center gap-5 px-6 mb-5 mt-3">
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-4 w-[40%] rounded-full" />
</View>
<View className="flex-row items-center gap-5 px-6 mb-5 mt-3">
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-4 w-[50%] rounded-full" />
</View>
<View className="flex-row items-center gap-5 px-6 mb-5 mt-3">
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-4 w-[30%] rounded-full" />
</View>
</>
)
}
2 changes: 1 addition & 1 deletion apps/mobile/components/common/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function Toolbar() {
</View>
</TouchableOpacity>
<Link href="/new-record" asChild>
<Button size="icon">
<Button size="icon" className="h-11 w-11">
<PlusIcon className="size-6 text-primary-foreground" />
</Button>
</Link>
Expand Down
38 changes: 38 additions & 0 deletions apps/mobile/components/home/wallet-statistics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useWallets } from '@/queries/wallet'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { Pressable, View } from 'react-native'
import { Skeleton } from '../ui/skeleton'
import { Text } from '../ui/text'

export function WalletStatistics() {
const { i18n } = useLingui()
const { data: walletAccounts, isLoading } = useWallets()

/**
* TODO: Calculate correct amount with currency exchange rate
* base on the user's preferred currency
*/
const currentBalance = walletAccounts?.reduce(
(acc, walletAccount) => acc + (walletAccount?.balance ?? 0),
0,
)

return (
<View className="gap-3">
<Pressable className="border-b border-primary self-start">
<Text className="w-fit self-start leading-tight">
{t(i18n)`Current balance`}
</Text>
</Pressable>
{isLoading ? (
<Skeleton className="w-44 h-10" />
) : (
<Text className="font-semibold text-4xl">
{currentBalance?.toLocaleString() || '0.00'}{' '}
<Text className="text-muted-foreground font-normal">VND</Text>
</Text>
)}
</View>
)
}
18 changes: 18 additions & 0 deletions apps/mobile/components/transaction/handy-arrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Svg, { type SvgProps, Path } from 'react-native-svg'

export const HandyArrow = (props: SvgProps) => (
<Svg width={51} height={87} fill="none" {...props}>
<Path
stroke="currentColor"
strokeLinecap="round"
strokeWidth={2}
d="M1.715 1.547c.168.671 2.887.133 3.217.102 5.252-.487 10.983-1.296 16.054.658 5.617 2.165 10.635 7.488 13.7 12.516 3.101 5.087 5.733 10.7 6.916 16.58 1.198 5.958-3.224 11.726-7.544 15.44-1.479 1.272-3.105 2.249-5.147 1.99-7.02-.892-3.242-8.432-.819-12.078 2.417-3.636 6.537-4.663 10.586-2.924 4.976 2.138 7.97 7.096 9.62 12.048 1.535 4.603 1.253 9.363.38 14.066-1.455 7.845-4.375 15.472-6.433 23.189"
/>
<Path
stroke="currentColor"
strokeLinecap="round"
strokeWidth={2}
d="M37.034 74.607c0 2.113 1.609 4.407 2.515 6.2.444.876 1.866 4.829 3.217 4.649.756-.101 2.227-2.21 2.778-2.72 1.51-1.4 2.45-3.035 3.86-4.445"
/>
</Svg>
)
Loading