Skip to content

Commit 08dce20

Browse files
authored
feat: make the 404 page nicer and implement 404 handling (#117)
1 parent eed7085 commit 08dce20

File tree

5 files changed

+132
-15
lines changed

5 files changed

+132
-15
lines changed

src/app/i/[id]/helpers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { isNotFoundError } from "@/lib/utils";
2+
import { api } from "@/trpc/server";
3+
4+
export async function getInvoiceMeLink(id: string) {
5+
try {
6+
return await api.invoiceMe.getById.query(id);
7+
} catch (error) {
8+
if (isNotFoundError(error)) {
9+
return null;
10+
}
11+
throw error;
12+
}
13+
}

src/app/i/[id]/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { Footer } from "@/components/footer";
33
import { Header } from "@/components/header";
44
import { InvoiceCreator } from "@/components/invoice-creator";
55
import { getInvoiceCount } from "@/lib/helpers/invoice";
6-
import { api } from "@/trpc/server";
76
import { ArrowLeft } from "lucide-react";
87
import type { Metadata } from "next";
98
import Link from "next/link";
109
import { notFound, redirect } from "next/navigation";
10+
import { getInvoiceMeLink } from "./helpers";
11+
import { api } from "@/trpc/server";
1112

1213
export const metadata: Metadata = {
1314
title: "Invoice Me | EasyInvoice",
@@ -20,9 +21,8 @@ export default async function InvoiceMePage({
2021
params: { id: string };
2122
}) {
2223
// TODO solve unauthenticated access
23-
// TODO solve not found error like the subscription plan page
24-
const invoiceMeLink = await api.invoiceMe.getById.query(params.id);
2524
const currentUser = await api.auth.getSessionInfo.query();
25+
const invoiceMeLink = await getInvoiceMeLink(params.id);
2626

2727
if (!invoiceMeLink) {
2828
notFound();

src/app/invoices/[ID]/helpers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { isNotFoundError } from "@/lib/utils";
2+
import { api } from "@/trpc/server";
3+
4+
export async function getInvoice(id: string) {
5+
try {
6+
return await api.invoice.getById.query(id);
7+
} catch (error) {
8+
if (isNotFoundError(error)) {
9+
return null;
10+
}
11+
throw error;
12+
}
13+
}

src/app/invoices/[ID]/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { formatDate } from "@/lib/date-utils";
99
import { api } from "@/trpc/server";
1010
import type { Metadata } from "next";
1111
import { notFound } from "next/navigation";
12+
import { getInvoice } from "./helpers";
1213
export const metadata: Metadata = {
1314
title: "Invoice Payment | EasyInvoice",
1415
description: "Process payment for your invoice",
@@ -25,7 +26,7 @@ export default async function PaymentPage({
2526
}: {
2627
params: { ID: string };
2728
}) {
28-
const invoice = await api.invoice.getById.query(params.ID);
29+
const invoice = await getInvoice(params.ID);
2930

3031
if (!invoice) {
3132
notFound();

src/app/not-found.tsx

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,114 @@
1+
import { getCurrentSession } from "@/server/auth";
2+
import { DollarSign, FileText, Home, Lock, Wallet, Zap } from "lucide-react";
13
import Link from "next/link";
24

3-
export default function NotFound() {
5+
export default async function NotFound() {
6+
const { user } = await getCurrentSession();
7+
48
return (
5-
<div className="min-h-screen flex items-center justify-center bg-gray-50">
6-
<div className="max-w-md w-full text-center">
9+
<div className="min-h-screen flex flex-col items-center justify-center bg-gray-50 px-6">
10+
<div className="max-w-2xl w-full text-center">
711
<div className="mb-8">
8-
<h1 className="text-6xl font-bold text-gray-900 mb-4">404</h1>
9-
<h2 className="text-2xl font-semibold text-gray-700 mb-2">
10-
Not Found
11-
</h2>
12+
<div className="w-16 h-16 rounded-xl bg-black flex items-center justify-center mx-auto mb-6">
13+
<span className="text-white font-bold text-xl">EI</span>
14+
</div>
15+
</div>
16+
17+
<div className="mb-8">
18+
<h1 className="text-8xl font-bold text-gray-900 mb-4">404</h1>
19+
<div className="flex items-center justify-center gap-2 mb-4">
20+
<Wallet className="w-5 h-5 text-gray-600" />
21+
<span className="text-lg font-medium text-gray-700">
22+
Page Not Found
23+
</span>
24+
</div>
25+
<p className="text-gray-600 mb-2">
26+
The page you're looking for doesn't exist or may have been moved.
27+
</p>
1228
<p className="text-gray-600">
13-
Sorry, we couldn't find the page you're looking for.
29+
Your account and invoices remain secure.
1430
</p>
1531
</div>
1632

33+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
34+
<Link
35+
href="/payouts"
36+
className="shadow-md group p-6 bg-white rounded-lg border border-gray-200 hover:border-gray-300 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2"
37+
>
38+
<div className="w-12 h-12 rounded-lg bg-blue-100 flex items-center justify-center mx-auto mb-4 group-hover:bg-blue-200 transition-colors">
39+
<DollarSign className="w-6 h-6 text-blue-600" />
40+
</div>
41+
<h3 className="font-semibold text-gray-900 mb-2">Payouts</h3>
42+
<p className="text-sm text-gray-600">
43+
Single, batch or recurring payouts
44+
</p>
45+
</Link>
46+
47+
{user ? (
48+
<Link
49+
href="/invoices/create"
50+
className="shadow-md group p-6 bg-white rounded-lg border border-gray-200 hover:border-gray-300 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2"
51+
>
52+
<div className="w-12 h-12 rounded-lg bg-purple-100 flex items-center justify-center mx-auto mb-4 group-hover:bg-purple-200 transition-colors">
53+
<Zap className="w-6 h-6 text-purple-600" />
54+
</div>
55+
<h3 className="font-semibold text-gray-900 mb-2">
56+
Create Invoice
57+
</h3>
58+
<p className="text-sm text-gray-600">
59+
Start a new payment request
60+
</p>
61+
</Link>
62+
) : (
63+
<div className="shadow-md p-6 bg-white rounded-lg border border-gray-200 opacity-75 cursor-not-allowed">
64+
<div className="w-12 h-12 rounded-lg bg-gray-100 flex items-center justify-center mx-auto mb-4">
65+
<Lock className="w-6 h-6 text-gray-500" />
66+
</div>
67+
<h3 className="font-semibold text-gray-900 mb-2">
68+
Sign in to create invoices
69+
</h3>
70+
<p className="text-sm text-gray-600">
71+
Start a new payment request
72+
</p>
73+
</div>
74+
)}
75+
76+
{user ? (
77+
<Link
78+
href="/subscription-plans"
79+
className="shadow-md group p-6 bg-white rounded-lg border border-gray-200 hover:border-gray-300 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2"
80+
>
81+
<div className="w-12 h-12 rounded-lg bg-green-100 flex items-center justify-center mx-auto mb-4 group-hover:bg-green-200 transition-colors">
82+
<FileText className="w-6 h-6 text-green-600" />
83+
</div>
84+
<h3 className="font-semibold text-gray-900 mb-2">
85+
Subscription Plans
86+
</h3>
87+
<p className="text-sm text-gray-600">
88+
Manage your subscription plans
89+
</p>
90+
</Link>
91+
) : (
92+
<div className="shadow-md p-6 bg-white rounded-lg border border-gray-200 opacity-75 cursor-not-allowed">
93+
<div className="w-12 h-12 rounded-lg bg-gray-100 flex items-center justify-center mx-auto mb-4">
94+
<Lock className="w-6 h-6 text-gray-500" />
95+
</div>
96+
<h3 className="font-semibold text-gray-900 mb-2">
97+
Sign in to manage subscription plans
98+
</h3>
99+
<p className="text-sm text-gray-600">
100+
View and manage your subscription options
101+
</p>
102+
</div>
103+
)}
104+
</div>
105+
17106
<Link
18-
href="/"
19-
className="inline-flex items-center px-6 py-3 bg-primary text-white font-medium rounded-lg hover:bg-blue-700 transition-colors duration-200"
107+
href="/dashboard"
108+
className="inline-flex items-center gap-2 px-6 py-3 bg-black text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2"
20109
>
21-
Go Home
110+
<Home className="w-4 h-4" />
111+
Back to Dashboard
22112
</Link>
23113
</div>
24114
</div>

0 commit comments

Comments
 (0)