Skip to content

Commit 10e5d7a

Browse files
committed
feature: adding thank you page
1 parent 9b619e1 commit 10e5d7a

3 files changed

Lines changed: 227 additions & 2 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { useRouter } from 'next/navigation';
3+
import ThankYouPage from '../page';
4+
5+
// Mock next/navigation
6+
jest.mock('next/navigation', () => ({
7+
useRouter: jest.fn(),
8+
}));
9+
10+
// Mock framer-motion
11+
jest.mock('framer-motion', () => ({
12+
motion: {
13+
div: ({ children, variants, initial, animate, transition, ...props }: any) =>
14+
<div {...props}>{children}</div>,
15+
svg: ({ children, variants, initial, animate, ...props }: any) =>
16+
<svg {...props}>{children}</svg>,
17+
path: ({ variants, ...props }: any) => <path {...props} />,
18+
h1: ({ children, variants, ...props }: any) => <h1 {...props}>{children}</h1>,
19+
p: ({ children, variants, ...props }: any) => <p {...props}>{children}</p>,
20+
},
21+
AnimatePresence: ({ children }: any) => children,
22+
}));
23+
24+
const mockPush = jest.fn();
25+
26+
describe('ThankYouPage', () => {
27+
beforeEach(() => {
28+
(useRouter as jest.Mock).mockReturnValue({
29+
push: mockPush,
30+
});
31+
mockPush.mockClear();
32+
});
33+
34+
it('renders thank you message', () => {
35+
render(<ThankYouPage />);
36+
37+
expect(screen.getByText(/thank you/i)).toBeInTheDocument();
38+
expect(screen.getByText(/message has been sent/i)).toBeInTheDocument();
39+
});
40+
41+
it('renders animated green checkbox', () => {
42+
render(<ThankYouPage />);
43+
44+
const checkmark = screen.getByTestId('success-checkmark');
45+
expect(checkmark).toBeInTheDocument();
46+
expect(checkmark).toHaveClass('text-green-500');
47+
});
48+
49+
it('renders back to home link', () => {
50+
render(<ThankYouPage />);
51+
52+
const backButton = screen.getByRole('button', { name: /back to home/i });
53+
expect(backButton).toBeInTheDocument();
54+
});
55+
56+
it('uses proper typography fonts', () => {
57+
render(<ThankYouPage />);
58+
59+
const heading = screen.getByRole('heading');
60+
expect(heading).toHaveClass('font-mono');
61+
});
62+
63+
it('follows design theme colors', () => {
64+
render(<ThankYouPage />);
65+
66+
const container = screen.getByTestId('thank-you-container');
67+
expect(container).toHaveClass('bg-background');
68+
expect(container).toHaveClass('text-text');
69+
});
70+
71+
it('has proper responsive layout', () => {
72+
render(<ThankYouPage />);
73+
74+
const container = screen.getByTestId('thank-you-container');
75+
expect(container).toHaveClass('min-h-screen');
76+
expect(container).toHaveClass('flex');
77+
expect(container).toHaveClass('items-center');
78+
expect(container).toHaveClass('justify-center');
79+
});
80+
});

src/app/thank-you/page.tsx

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
'use client';
2+
3+
import { motion } from 'framer-motion';
4+
import { useRouter } from 'next/navigation';
5+
import { Button } from '@/components/ui';
6+
import { Card, CardContent, CardHeader } from '@/components/ui/Card';
7+
8+
// Animation variants for the success checkmark
9+
const checkmarkVariants = {
10+
hidden: {
11+
pathLength: 0,
12+
opacity: 0,
13+
},
14+
visible: {
15+
pathLength: 1,
16+
opacity: 1,
17+
transition: {
18+
pathLength: { duration: 0.6, ease: "easeInOut" },
19+
opacity: { duration: 0.3 }
20+
}
21+
}
22+
};
23+
24+
// Container animation variants
25+
const containerVariants = {
26+
hidden: {
27+
opacity: 0,
28+
y: 20,
29+
},
30+
visible: {
31+
opacity: 1,
32+
y: 0,
33+
transition: {
34+
duration: 0.8,
35+
ease: "easeOut",
36+
staggerChildren: 0.2
37+
}
38+
}
39+
};
40+
41+
// Item animation variants
42+
const itemVariants = {
43+
hidden: {
44+
opacity: 0,
45+
y: 20,
46+
},
47+
visible: {
48+
opacity: 1,
49+
y: 0,
50+
transition: {
51+
duration: 0.6,
52+
ease: "easeOut"
53+
}
54+
}
55+
};
56+
57+
export default function ThankYouPage() {
58+
const router = useRouter();
59+
60+
const handleBackToHome = () => {
61+
router.push('/');
62+
};
63+
64+
return (
65+
<div
66+
className="min-h-screen flex items-center justify-center bg-background text-text px-4"
67+
data-testid="thank-you-container"
68+
>
69+
<motion.div
70+
variants={containerVariants}
71+
initial="hidden"
72+
animate="visible"
73+
className="w-full max-w-md"
74+
>
75+
<Card className="bg-surface border border-muted/20 shadow-lg" variant="elevated">
76+
<CardHeader className="text-center pb-4">
77+
<motion.div
78+
variants={itemVariants}
79+
className="mx-auto mb-6 relative"
80+
>
81+
{/* Animated green circle background */}
82+
<motion.div
83+
initial={{ scale: 0 }}
84+
animate={{ scale: 1 }}
85+
transition={{
86+
delay: 0.2,
87+
duration: 0.5,
88+
ease: "easeOut"
89+
}}
90+
className="w-16 h-16 rounded-full bg-green-100 dark:bg-green-900/20 flex items-center justify-center"
91+
>
92+
{/* Animated checkmark SVG */}
93+
<motion.svg
94+
width="32"
95+
height="32"
96+
viewBox="0 0 24 24"
97+
fill="none"
98+
className="text-green-500"
99+
data-testid="success-checkmark"
100+
initial="hidden"
101+
animate="visible"
102+
>
103+
<motion.path
104+
d="M20 6L9 17l-5-5"
105+
stroke="currentColor"
106+
strokeWidth="2"
107+
strokeLinecap="round"
108+
strokeLinejoin="round"
109+
variants={checkmarkVariants}
110+
/>
111+
</motion.svg>
112+
</motion.div>
113+
</motion.div>
114+
115+
<motion.h1
116+
variants={itemVariants}
117+
className="text-2xl font-mono font-semibold text-text mb-2"
118+
>
119+
Thank You!
120+
</motion.h1>
121+
122+
<motion.p
123+
variants={itemVariants}
124+
className="text-muted font-normal"
125+
>
126+
Your message has been sent successfully. I'll get back to you as soon as possible.
127+
</motion.p>
128+
</CardHeader>
129+
130+
<CardContent className="text-center">
131+
<motion.div variants={itemVariants}>
132+
<Button
133+
onClick={handleBackToHome}
134+
className="w-full bg-accent hover:bg-accent/90 text-background font-medium transition-all duration-200 hover:scale-[1.02] hover:shadow-lg"
135+
size="lg"
136+
>
137+
Back to Home
138+
</Button>
139+
</motion.div>
140+
</CardContent>
141+
</Card>
142+
</motion.div>
143+
</div>
144+
);
145+
}

src/components/ui/Card.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
22
import { cn } from '@/lib';
33

44
const cardVariants = cva(
5-
'rounded-lg border bg-card text-card-foreground shadow-sm transition-all duration-200',
5+
'rounded-lg border bg-surface text-text shadow-sm transition-all duration-200',
66
{
77
variants: {
88
variant: {
@@ -19,7 +19,7 @@ const cardVariants = cva(
1919

2020
const cardHeaderVariants = cva('flex flex-col space-y-1.5 p-6');
2121
const cardTitleVariants = cva('text-2xl font-semibold leading-none tracking-tight');
22-
const cardDescriptionVariants = cva('text-sm text-muted-foreground');
22+
const cardDescriptionVariants = cva('text-sm text-muted');
2323
const cardContentVariants = cva('p-6 pt-0');
2424
const cardFooterVariants = cva('flex items-center p-6 pt-0');
2525

0 commit comments

Comments
 (0)