Skip to content

Commit

Permalink
feat: payment confirm screen
Browse files Browse the repository at this point in the history
  • Loading branch information
mrevanzak committed Nov 14, 2023
1 parent f9deb0b commit b951d88
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 16 deletions.
1 change: 1 addition & 0 deletions apps/expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@trpc/react-query": "next",
"@trpc/server": "next",
"expo": "^49.0.13",
"expo-clipboard": "~4.3.1",
"expo-constants": "~14.4.2",
"expo-linear-gradient": "~12.3.0",
"expo-linking": "~5.0.2",
Expand Down
15 changes: 13 additions & 2 deletions apps/expo/src/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function AuthLayout() {
options={{
header: (props) => <Header {...props} />,
contentStyle: {
backgroundColor: 'white',
backgroundColor: "white",
},
}}
/>
Expand All @@ -45,7 +45,18 @@ export default function AuthLayout() {
name="checkout"
options={{
headerTitle: "Pengiriman",
headerTitleAlign: "center",
}}
/>
<Stack.Screen
name="payment"
options={{
headerTitle: "Pembayaran",
}}
/>
<Stack.Screen
name="payment-confirm"
options={{
headerTitle: "Konfirmasi Pembayaran",
}}
/>
<Stack.Screen
Expand Down
18 changes: 10 additions & 8 deletions apps/expo/src/app/(app)/checkout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TouchableOpacity,
View,
} from "react-native-ui-lib";
import { Link, useLocalSearchParams } from "expo-router";
import { Link, router, useLocalSearchParams } from "expo-router";
import Input from "@/components/forms/Input";
import RadioButton from "@/components/forms/RadioButton";
import { api } from "@/utils/api";
Expand All @@ -25,10 +25,10 @@ const schema = z.object({
const ONGKIR = 40000;

export default function CheckoutScreen() {
const { productId } = useLocalSearchParams();
const { productId } = useLocalSearchParams<{ productId: string }>();

const { data: product } = api.product.showProduct.useQuery({
id: productId as string,
id: productId,
});
const { data: address } = api.user.getDefaultAddress.useQuery();
const { mutate, isPending } = api.order.checkout.useMutation();
Expand All @@ -44,13 +44,15 @@ export default function CheckoutScreen() {
note: data.note,
addressId: address.id,
productId: productId as string,
totalPrice: product.price + 10000,
totalPrice: product.price + ONGKIR,
courier: data.courier,
},
{
onSuccess: () => {
console.log("success");
// void utils.user.getAddresses.invalidate();
onSuccess: ({ orderId }) => {
router.replace({
pathname: "/payment",
params: { orderId },
});
},
},
);
Expand Down Expand Up @@ -118,7 +120,7 @@ export default function CheckoutScreen() {
</View>
<View row spread>
<Text text80>Total</Text>
<Text text80>{rupiahFormatter(product?.price ?? 0 + ONGKIR)}</Text>
<Text text80>{product?.price && rupiahFormatter(product.price + ONGKIR)}</Text>
</View>
</View>
<Button
Expand Down
63 changes: 63 additions & 0 deletions apps/expo/src/app/(app)/payment-confirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from "react";
import { Button, View } from "react-native-ui-lib";
import { useLocalSearchParams } from "expo-router";
import Input from "@/components/forms/Input";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { FormProvider, useForm } from "react-hook-form";
import { z } from "zod";

const schema = z.object({
proof: z.string(),
bankName: z.string(),
bankAccount: z.string(),
bankHolder: z.string(),
});

export default function PaymentConfirmScreen() {
const { orderId } = useLocalSearchParams<{ orderId: string }>();

const { mutate } = api.order.confirmPayment.useMutation();
const methods = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
});
const { handleSubmit } = methods;
const onSubmit = handleSubmit((data) => {
mutate({
...data,
orderId,
});
});

return (
<View bg-white br50 flex padding-s4 className="rounded-b-none">
<FormProvider {...methods}>
<Input
id="bankName"
label="Nama Bank"
multiline
placeholder="Masukan nama bank"
/>
<Input
id="bankAccount"
label="Nomor Rekening"
multiline
placeholder="Masukan nomor rekening"
/>
<Input
id="bankHolder"
label="Nama Pemilik Rekening"
multiline
placeholder="Masukan nama pemilik rekening"
/>
</FormProvider>
<Button
label="Simpan"
onPress={onSubmit}
bg-primary
br40
// disabled={isPending}
/>
</View>
);
}
114 changes: 114 additions & 0 deletions apps/expo/src/app/(app)/payment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from "react";
import { Alert } from "react-native";
import { Text, TouchableOpacity, View } from "react-native-ui-lib";
import * as Clipboard from "expo-clipboard";
import { Link, useLocalSearchParams } from "expo-router";
import { api } from "@/utils/api";
import colors from "@/utils/colors";
import rupiahFormatter from "@/utils/rupiahFormatter";
import { Ionicons } from "@expo/vector-icons";

const BANK_ACCOUNT = [
{
name: "BNI",
number: "12345678910",
},
{
name: "BCA",
number: "12345678910",
},
{
name: "MANDIRI",
number: "12345678910",
},
{
name: "BRI",
number: "12345678910",
},
];

export default function PaymentScreen() {
const { orderId } = useLocalSearchParams<{ orderId: string }>();
const { data: orders } = api.order.showOrder.useQuery({
id: orderId,
});

return (
<View bg-white br50 flex padding-s4 className="rounded-b-none">
<View
paddingV-s2
paddingH-s4
br40
className="border-primary mb-4 space-y-1 border"
>
<Text text80 primary marginB-s1>
Rincian Pembelian
</Text>
<Text text70BO primary>
{orders?.product.name}
</Text>
<Text primary>
Penerima:{" "}
<Text>
{orders?.address.recipient} - {orders?.address.phoneNumber}
</Text>
</Text>
<Text primary>
Alamat:{" "}
<Text>
{orders?.address.address} - {orders?.address.zipCode}
</Text>
</Text>
<Text primary>
Catatan: <Text>{orders?.note ?? "-"}</Text>
</Text>
<Text primary>
Kurir: <Text>{orders?.courier}</Text>
</Text>
<View row spread center>
<Text primary>TOTAL:</Text>
<View flex height={1} bg-black marginH-s2></View>
<Text primary text70BO>
{rupiahFormatter(orders?.totalPrice)}
</Text>
</View>
</View>
<View
paddingV-s2
paddingH-s4
br40
className="border-primary mb-4 space-y-1 border"
>
<Text text80 primary marginB-s1>
Transfer ke Vivat Marketplace
</Text>
{BANK_ACCOUNT.map((bank) => (
<Text
key={bank.name}
onPress={async () => {
await Clipboard.setStringAsync(bank.number);
Alert.alert("Berhasil menyalin nomor rekening");
}}
>
{bank.name}: {bank.number} - Vivat Marketplace
</Text>
))}
</View>
<Link href="/payment-confirm" asChild>
<TouchableOpacity
row
spread
paddingV-s2
paddingH-s4
br40
className="border-primary mb-4 border"
>
<Text text70 primary>
Unggah Bukti Pembayaran
</Text>
<Ionicons name="chevron-forward" size={24} color={colors.primary} />
</TouchableOpacity>
</Link>
</View>
);
}
9 changes: 6 additions & 3 deletions apps/expo/src/app/(app)/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import rupiahFormatter from "@/utils/rupiahFormatter";
import { FlashList } from "@shopify/flash-list";

export default function SearchScreen() {
const { categoryId, search } = useLocalSearchParams();
const [debouncedSearch] = useDebouncedValue(search as string, 500);
const { categoryId, search } = useLocalSearchParams<{
categoryId: string;
search: string;
}>();
const [debouncedSearch] = useDebouncedValue(search, 500);
const { data, isFetching, refetch } = api.product.getProducts.useQuery({
query: debouncedSearch ?? "",
categoryId: categoryId as string,
categoryId,
});

return (
Expand Down
1 change: 0 additions & 1 deletion apps/expo/src/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.png";
declare module "react-native-parallax-scroll-view";
2 changes: 2 additions & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
"@trpc/server": "next",
"@vivat/db": "^0.1.0",
"superjson": "1.13.1",
"uuid": "^9.0.1",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/uuid": "^9.0.7",
"@vivat/eslint-config": "^0.2.0",
"@vivat/prettier-config": "^0.1.0",
"@vivat/tsconfig": "^0.1.0",
Expand Down
47 changes: 45 additions & 2 deletions packages/api/src/router/orders.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
import { insertOrderParams, orders } from "@vivat/db/schema/orders";
import { v4 } from "uuid";

import { eq } from "@vivat/db";
import {
insertOrderParams,
orderIdSchema,
orders,
} from "@vivat/db/schema/orders";
import { createPaymentParams, payments } from "@vivat/db/schema/payments";

import { createTRPCRouter, protectedProcedure } from "../trpc";

export const orderRouter = createTRPCRouter({
checkout: protectedProcedure
.input(insertOrderParams)
.mutation(async ({ input, ctx }) => {
return await ctx.db.insert(orders).values(input);
const orderId = v4();

await ctx.db.insert(orders).values({
...input,
id: orderId,
});
return { orderId };
}),
showOrder: protectedProcedure
.input(orderIdSchema)
.query(async ({ input, ctx }) => {
return (
(await ctx.db.query.orders.findFirst({
with: {
product: true,
address: true,
},
where: (order, { eq }) => eq(order.id, input.id),
})) ?? null
);
}),
confirmPayment: protectedProcedure
.input(createPaymentParams)
.mutation(async ({ input, ctx }) => {
return await ctx.db.transaction(async (db) => {
await db
.update(payments)
.set(input)
.where(eq(payments.orderId, input.orderId));
await db
.update(orders)
.set({
status: "payment",
})
.where(eq(orders.id, input.orderId));
});
}),
});
2 changes: 2 additions & 0 deletions packages/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import * as categories from "./schema/categories";
import * as orders from "./schema/orders";
import * as products from "./schema/products";
import * as users from "./schema/users";
import * as payments from "./schema/payments";

export const schema = {
...users,
...products,
...categories,
...addresses,
...orders,
...payments,
};

export { mySqlTable as tableCreator } from "./schema/_table";
Expand Down
Loading

0 comments on commit b951d88

Please sign in to comment.