generated from clerk/t3-turbo-and-clerk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Diego Romero
committed
Nov 26, 2023
1 parent
dc68076
commit 94500c8
Showing
9 changed files
with
200 additions
and
40 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Pressable } from "react-native"; | ||
import type { RootStackScreenProps } from "../types/navigation"; | ||
import AuthenticationCard from "../components/auth/AuthenticationCard"; | ||
|
||
function AuthenticationScreenModal({ | ||
navigation, | ||
}: RootStackScreenProps<"Sign In">) { | ||
return ( | ||
<Pressable | ||
className="h-full justify-center bg-gray-600 px-2" | ||
style={{ backgroundColor: "rgba(75, 85, 99, .3)" }} | ||
onPressOut={() => navigation.pop(1)} | ||
onPress={(event) => { | ||
if (event.target == event.currentTarget) { | ||
navigation.pop(1); | ||
} | ||
}} | ||
> | ||
<Pressable> | ||
<AuthenticationCard /> | ||
</Pressable> | ||
</Pressable> | ||
); | ||
} | ||
|
||
export default AuthenticationScreenModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,102 @@ | ||
import { useAtomValue } from "jotai"; | ||
import { useAtom, useAtomValue } from "jotai"; | ||
import { cartAtom, cartTotalAtom } from "../atoms/cart"; | ||
import CartItem from "../components/CartItem"; | ||
import { Text, View } from "react-native"; | ||
import { Image, Pressable, Text, View } from "react-native"; | ||
import { FlatList } from "react-native-gesture-handler"; | ||
import { useMemo } from "react"; | ||
import { HomeTabScreenProps } from "../types/navigation"; | ||
import { useAuth } from "@clerk/clerk-expo"; | ||
import { trpc } from "../utils/trpc"; | ||
|
||
function CartListScreen() { | ||
function CartListScreen({ navigation }: HomeTabScreenProps<"Cart">) { | ||
const cart = useAtomValue(cartAtom); | ||
|
||
const data = useMemo(() => Object.entries(cart), [cart]); | ||
const total = useAtomValue(cartTotalAtom); | ||
|
||
return ( | ||
<View className="flex-1 bg-gray-50"> | ||
<View className="flex-1 bg-white"> | ||
<View className="mb-2.5 h-12 justify-center border-b border-b-gray-200 bg-white shadow-sm"> | ||
<Text className="ml-2.5 text-lg ">Shopping Cart</Text> | ||
</View> | ||
|
||
<View className="flex-1 px-2"> | ||
<View className=" flex flex-row items-center justify-between"> | ||
<Text className="text-lg"> | ||
<Text className="text-xl font-medium">Total: </Text>C${" "} | ||
{total.toFixed(2)} | ||
</Text> | ||
</View> | ||
|
||
<CartHeader navigation={navigation} /> | ||
<View className="mt-1.5 mb-2.5 border-b-[0.5px] border-b-gray-400" /> | ||
<FlatList | ||
data={data} | ||
renderItem={(item) => ( | ||
<CartItem | ||
id={Number(item.item[0])} | ||
key={item.item[0]} | ||
quantity={item.item[1]} | ||
|
||
{data.length > 0 ? ( | ||
<FlatList | ||
data={data} | ||
renderItem={(item) => ( | ||
<CartItem | ||
id={Number(item.item[0])} | ||
key={item.item[0]} | ||
quantity={item.item[1]} | ||
/> | ||
)} | ||
ItemSeparatorComponent={() => <View className="mt-2.5" />} | ||
ListFooterComponent={() => <View className="mt-2.5" />} | ||
contentContainerStyle={{ justifyContent: "center" }} | ||
/> | ||
) : ( | ||
<View className="h-full items-center justify-center pb-48"> | ||
<Image | ||
source={require("../../assets/emptyCart.png")} | ||
className="h-72 w-72 " | ||
/> | ||
)} | ||
ItemSeparatorComponent={() => <View className="mt-2.5" />} | ||
ListFooterComponent={() => <View className="mt-2.5" />} | ||
/> | ||
<Text className="text-xl text-gray-700">Your cart is empty</Text> | ||
</View> | ||
)} | ||
</View> | ||
</View> | ||
); | ||
} | ||
|
||
function CartHeader({ | ||
navigation, | ||
}: { | ||
navigation: HomeTabScreenProps<"Cart">["navigation"]; | ||
}) { | ||
const { isSignedIn } = useAuth(); | ||
const total = useAtomValue(cartTotalAtom); | ||
const [cart, setCart] = useAtom(cartAtom); | ||
const { mutate, isLoading } = trpc.order.create.useMutation(); | ||
|
||
const onCreateOrder = () => { | ||
const cartEntries = Object.entries(cart).map(([key, value]) => ({ | ||
id: Number(key), | ||
quantity: value, | ||
})); | ||
|
||
if (cartEntries.length > 0) { | ||
const input = { | ||
total: total, | ||
items: cartEntries, | ||
}; | ||
mutate(input, { | ||
onSuccess: () => { | ||
setCart({}); | ||
}, | ||
}); | ||
} | ||
}; | ||
|
||
return ( | ||
<View className="flex flex-row items-center justify-between"> | ||
<Text className="text-lg"> | ||
<Text className="text-xl font-medium">Total: </Text>C$ | ||
{total.toFixed(2)} | ||
</Text> | ||
<Pressable | ||
className="rounded bg-emerald-500 p-1.5 active:bg-emerald-600" | ||
onPress={!isSignedIn ? () => navigation.push("Sign In") : onCreateOrder} | ||
disabled={isLoading} | ||
> | ||
<Text className="text-white"> | ||
{isSignedIn ? "Create Order" : "Log In to Buy"} | ||
</Text> | ||
</Pressable> | ||
</View> | ||
); | ||
} | ||
|
||
export default CartListScreen; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { router, protectedProcedure } from "../trpc"; | ||
import { z } from "zod"; | ||
|
||
export const orderRouter = router({ | ||
create: protectedProcedure | ||
.input( | ||
z.object({ | ||
total: z.number().nonnegative(), | ||
items: z | ||
.object({ | ||
id: z.number().positive(), | ||
quantity: z.number().nonnegative(), | ||
}) | ||
.array(), | ||
}), | ||
) | ||
.mutation(async ({ ctx, input }) => { | ||
const itemIds = input.items.map((item) => item.id); | ||
const items = await ctx.prisma.items.findMany({ | ||
where: { | ||
id: { in: itemIds }, | ||
}, | ||
}); | ||
|
||
const q: Record<number, number> = {}; | ||
input.items.forEach((item) => { | ||
q[item.id] = item.quantity; | ||
}); | ||
|
||
return await ctx.prisma.orders.create({ | ||
data: { | ||
status: "Placed", | ||
total: input.total, | ||
user_id: ctx.auth.userId, | ||
orderitems: { | ||
create: items.map((item) => ({ | ||
name: item.name, | ||
price: item.price, | ||
quantity: q[item.id] ?? 0, | ||
})), | ||
}, | ||
}, | ||
include: { | ||
orderitems: true, | ||
}, | ||
}); | ||
}), | ||
}); |