Skip to content
Merged
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
42 changes: 21 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.7",
"@radix-ui/react-tooltip": "^1.2.8",
"@reown/appkit": "^1.6.8",
"@reown/appkit-adapter-ethers5": "^1.6.8",
"@tanstack/react-query": "^4.36.1",
Expand Down
16 changes: 15 additions & 1 deletion src/app/i/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { api } from "@/trpc/server";
import { ArrowLeft } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { notFound, redirect } from "next/navigation";

export const metadata: Metadata = {
title: "Invoice Me | EasyInvoice",
Expand All @@ -22,11 +22,16 @@ export default async function InvoiceMePage({
// TODO solve unauthenticated access
// TODO solve not found error like the subscription plan page
const invoiceMeLink = await api.invoiceMe.getById.query(params.id);
const currentUser = await api.auth.getSessionInfo.query();

if (!invoiceMeLink) {
notFound();
}

if (currentUser.user && currentUser.user.id === invoiceMeLink.user.id) {
redirect("/dashboard");
}

const invoiceCount = await getInvoiceCount(invoiceMeLink.user.id);

return (
Expand Down Expand Up @@ -54,6 +59,15 @@ export default async function InvoiceMePage({
clientEmail: invoiceMeLink.user.email ?? "",
userId: invoiceMeLink.user.id,
}}
currentUser={
currentUser.user
? {
id: currentUser.user.id,
name: currentUser.user.name ?? "",
email: currentUser.user.email ?? "",
}
: undefined
}
invoiceCount={invoiceCount}
/>
</main>
Expand Down
6 changes: 6 additions & 0 deletions src/components/batch-payout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table/table";

import {
PAYOUT_CURRENCIES,
type PayoutCurrency,
formatCurrencyLabel,
getPaymentCurrenciesForPayout,
} from "@/lib/constants/currencies";
import { handleBatchPayment } from "@/lib/helpers/batch-payment";

import { useSwitchNetwork } from "@/lib/hooks/use-switch-network";
import { payoutSchema } from "@/lib/schemas/payment";
import { api } from "@/trpc/react";
import { z } from "zod";
Expand All @@ -74,6 +77,7 @@ export type BatchPaymentFormValues = z.infer<typeof batchPaymentFormSchema>;

export function BatchPayout() {
const { mutateAsync: batchPay } = api.payment.batchPay.useMutation();
const { switchToPaymentNetwork } = useSwitchNetwork();

const [paymentStatus, setPaymentStatus] = useState<
"idle" | "processing" | "success" | "error"
Expand Down Expand Up @@ -211,6 +215,8 @@ export function BatchPayout() {
return;
}

await switchToPaymentNetwork(data.payouts[0].paymentCurrency);

try {
const ethersProvider = new ethers.providers.Web3Provider(walletProvider);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";

import {
RECURRING_PAYMENT_CURRENCIES,
formatCurrencyLabel,
} from "@/lib/constants/currencies";

import { useCreateRecurringPayment } from "@/lib/hooks/use-create-recurring-payment";
import { useSwitchNetwork } from "@/lib/hooks/use-switch-network";
import { paymentApiSchema } from "@/lib/schemas/payment";
import { RecurrenceFrequency } from "@/server/db/schema";
import { zodResolver } from "@hookform/resolvers/zod";
Expand All @@ -51,6 +54,8 @@ type RecurringPaymentFormValues = z.infer<typeof recurringPaymentFormSchema>;
export function CreateRecurringPaymentForm() {
const router = useRouter();

const { switchToPaymentNetwork } = useSwitchNetwork();

const { address, isConnected } = useAppKitAccount();
const { open } = useAppKit();
const { walletProvider } = useAppKitProvider("eip155");
Expand Down Expand Up @@ -91,6 +96,8 @@ export function CreateRecurringPaymentForm() {
return;
}

await switchToPaymentNetwork(data.invoiceCurrency);

const recurringPaymentCurrency = data.invoiceCurrency;
const recurringPaymentBody = {
payee: data.payee,
Expand Down
29 changes: 7 additions & 22 deletions src/components/dashboard/invoices-received.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table/table";
import { ID_TO_APPKIT_NETWORK, NETWORK_TO_ID } from "@/lib/constants/chains";
import { NETWORK_TO_ID } from "@/lib/constants/chains";
import { handleBatchPayment } from "@/lib/helpers/batch-payment";
import {
calculateTotalsByCurrency,
formatCurrencyTotals,
} from "@/lib/helpers/currency";
import { useSwitchNetwork } from "@/lib/hooks/use-switch-network";
import type { Request } from "@/server/db/schema";
import { api } from "@/trpc/react";
import {
useAppKit,
useAppKitAccount,
useAppKitNetwork,
useAppKitProvider,
} from "@reown/appkit/react";
import { ethers } from "ethers";
Expand Down Expand Up @@ -73,7 +73,7 @@ export const InvoicesReceived = ({
const { open } = useAppKit();
const { isConnected, address } = useAppKitAccount();
const { walletProvider } = useAppKitProvider("eip155");
const { chainId, switchNetwork } = useAppKitNetwork();
const { switchToChainId } = useSwitchNetwork();

const { data: invoices } = api.invoice.getAllIssuedToMe.useQuery(undefined, {
initialData: initialReceivedInvoices,
Expand Down Expand Up @@ -134,27 +134,12 @@ export const InvoicesReceived = ({
return;
}

const targetChain =
NETWORK_TO_ID[lastSelectedNetwork as keyof typeof NETWORK_TO_ID];

if (targetChain !== chainId) {
const targetAppkitNetwork =
ID_TO_APPKIT_NETWORK[targetChain as keyof typeof ID_TO_APPKIT_NETWORK];
try {
const targetChainId =
NETWORK_TO_ID[lastSelectedNetwork as keyof typeof NETWORK_TO_ID];

toast("Switching to network", {
description: `Switching to ${targetAppkitNetwork.name} network`,
});
await switchToChainId(targetChainId);

try {
switchNetwork(targetAppkitNetwork);
} catch (_) {
toast("Error switching network");
setIsPayingInvoices(false);
return;
}
}

try {
const ethersProvider = new ethers.providers.Web3Provider(
walletProvider as ethers.providers.ExternalProvider,
);
Expand Down
5 changes: 5 additions & 0 deletions src/components/direct-payout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";

import {
PAYOUT_CURRENCIES,
type PayoutCurrency,
formatCurrencyLabel,
getPaymentCurrenciesForPayout,
} from "@/lib/constants/currencies";

import { useSwitchNetwork } from "@/lib/hooks/use-switch-network";
import { paymentApiSchema } from "@/lib/schemas/payment";
import { api } from "@/trpc/react";
import type { z } from "zod";
Expand All @@ -57,6 +60,7 @@ export type DirectPaymentFormValues = z.infer<typeof directPaymentFormSchema>;

export function DirectPayment() {
const { mutateAsync: pay } = api.payment.pay.useMutation();
const { switchToPaymentNetwork } = useSwitchNetwork();

const [paymentStatus, setPaymentStatus] = useState<
"idle" | "processing" | "success" | "error"
Expand Down Expand Up @@ -118,6 +122,7 @@ export function DirectPayment() {
return;
}

await switchToPaymentNetwork(data.paymentCurrency);
setPaymentStatus("processing");

try {
Expand Down
17 changes: 12 additions & 5 deletions src/components/invoice-creator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,19 @@ export function InvoiceCreator({
const router = useRouter();
const isInvoiceMe = !!recipientDetails?.userId;
const utils = api.useUtils();
const { mutate: createInvoice, isLoading } = isInvoiceMe

const { mutateAsync: createInvoice, isLoading } = isInvoiceMe
? api.invoice.createFromInvoiceMe.useMutation({
onSuccess: () => {
toast.success("Invoice created successfully", {
description: "You can safely close this page now",
});
onSuccess: async () => {
if (!currentUser) {
toast.success("Invoice created successfully", {
description: "You can safely close this page now",
});
return;
}
toast.success("Invoice created successfully");
await utils.invoice.getAll.invalidate();
router.push("/dashboard");
},
onError: (error) => {
toast.error("Failed to create invoice", {
Expand Down
4 changes: 2 additions & 2 deletions src/components/invoice-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const checkPaymentDetailsApproval = (
interface InvoiceFormProps {
currentUser: User;
form: UseFormReturn<InvoiceFormValues>;
onSubmit: (data: InvoiceFormValues) => void;
onSubmit: (data: InvoiceFormValues) => Promise<void>;
isLoading: boolean;
recipientDetails?: {
clientName: string;
Expand Down Expand Up @@ -1037,7 +1037,7 @@ export function InvoiceForm({
<Button
type="submit"
className="bg-black hover:bg-zinc-800 text-white transition-colors"
disabled={isLoading || isSubmitting}
disabled={isLoading || isSubmitting || invoiceCreated}
>
{isLoading || isSubmitting
? "Creating..."
Expand Down
11 changes: 3 additions & 8 deletions src/components/payment-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { api } from "@/trpc/react";
import {
useAppKit,
useAppKitAccount,
useAppKitNetwork,
useAppKitProvider,
useDisconnect,
} from "@reown/appkit/react";
import { ethers } from "ethers";
import { AlertCircle, CheckCircle, Clock, Loader2, Wallet } from "lucide-react";

import { useSwitchNetwork } from "@/lib/hooks/use-switch-network";
import {
getPaymentSectionStatusClass,
getStatusDisplayText,
Expand Down Expand Up @@ -106,8 +106,8 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
const { open } = useAppKit();
const { disconnect } = useDisconnect();
const { isConnected, address } = useAppKitAccount();
const { chainId, switchToChainId } = useSwitchNetwork();
const { walletProvider } = useAppKitProvider("eip155");
const { chainId, switchNetwork } = useAppKitNetwork();
const [showRoutes, setShowRoutes] = useState(false);
const [selectedRoute, setSelectedRoute] = useState<PaymentRouteType | null>(
null,
Expand Down Expand Up @@ -343,12 +343,7 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
description: `Switching to ${targetAppkitNetwork?.name} network`,
});

try {
await switchNetwork(targetAppkitNetwork);
} catch (_) {
toast("Error switching network");
return;
}
await switchToChainId(targetChain);
}

const ethersProvider = new ethers.providers.Web3Provider(
Expand Down
Loading