diff --git a/nevo_frontend/__tests__/AboutPage.test.tsx b/nevo_frontend/__tests__/AboutPage.test.tsx new file mode 100644 index 0000000..61c4107 --- /dev/null +++ b/nevo_frontend/__tests__/AboutPage.test.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import AboutPage, { AboutPageSkeleton } from '@/app/about/page'; + +describe('AboutPage', () => { + it('renders mission statement', () => { + render(); + expect(screen.getByRole('heading', { name: 'Our Mission' })).toBeInTheDocument(); + expect(screen.getByText(/empower anyone, anywhere to create transparent/i)).toBeInTheDocument(); + }); + + it('renders company values section', () => { + render(); + expect(screen.getByRole('heading', { name: 'Our Values' })).toBeInTheDocument(); + expect(screen.getByText('Transparency')).toBeInTheDocument(); + expect(screen.getByText('Security')).toBeInTheDocument(); + expect(screen.getByText('Community')).toBeInTheDocument(); + expect(screen.getByText('Accessibility')).toBeInTheDocument(); + }); + + it('renders team section with member bios', () => { + render(); + expect(screen.getByRole('heading', { name: 'Meet the Team' })).toBeInTheDocument(); + expect(screen.getByText('Alex Morgan')).toBeInTheDocument(); + expect(screen.getByText('Founder & CEO')).toBeInTheDocument(); + expect(screen.getByText(/Blockchain enthusiast/i)).toBeInTheDocument(); + }); + + it('renders testimonials', () => { + render(); + expect(screen.getByRole('heading', { name: 'What They Say' })).toBeInTheDocument(); + expect(screen.getByText(/revolutionized how we collect donations/i)).toBeInTheDocument(); + expect(screen.getByText('Maria Santos')).toBeInTheDocument(); + }); + + it('renders contact information', () => { + render(); + expect(screen.getByRole('heading', { name: 'Get in Touch' })).toBeInTheDocument(); + expect(screen.getByText(/Have questions or want to learn more/i)).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'Email Us' })).toHaveAttribute('href', 'mailto:hello@nevo.app'); + expect(screen.getByRole('link', { name: 'Contact Form' })).toHaveAttribute('href', '/contact'); + }); + + it('renders social media links for team members', () => { + render(); + expect(screen.getByLabelText(/Alex Morgan's Twitter/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/Alex Morgan's GitHub/i)).toBeInTheDocument(); + }); + + it('is mobile responsive with proper text sizes', () => { + const { container } = render(); + const main = container.querySelector('main'); + expect(main).toHaveClass('max-w-5xl'); + }); +}); + +describe('AboutPageSkeleton', () => { + it('renders loading skeleton with accessibility attributes', () => { + render(); + const main = screen.getByRole('main'); + expect(main).toHaveAttribute('aria-busy', 'true'); + expect(main).toHaveAttribute('aria-label', 'Loading about page'); + }); + + it('renders skeleton placeholders', () => { + render(); + const skeletonElements = document.querySelectorAll('.animate-pulse'); + expect(skeletonElements.length).toBeGreaterThan(0); + }); +}); \ No newline at end of file diff --git a/nevo_frontend/__tests__/Skeleton.test.tsx b/nevo_frontend/__tests__/Skeleton.test.tsx new file mode 100644 index 0000000..cc53a86 --- /dev/null +++ b/nevo_frontend/__tests__/Skeleton.test.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Skeleton, SkeletonVariant } from '@/components/Skeleton'; + +describe('Skeleton', () => { + it('renders text variant by default', () => { + render(); + const container = document.querySelector('.space-y-2'); + expect(container).toBeInTheDocument(); + }); + + it('renders text variant with custom line count', () => { + render(); + const lines = document.querySelectorAll('.h-4'); + expect(lines.length).toBeGreaterThanOrEqual(5); + }); + + it('renders card variant', () => { + render(); + const card = document.querySelector('.rounded-lg.border'); + expect(card).toBeInTheDocument(); + }); + + it('renders image variant with default dimensions', () => { + render(); + const imageSkeleton = document.querySelector('.rounded-md'); + expect(imageSkeleton).toBeInTheDocument(); + }); + + it('applies custom width and height to image variant', () => { + render(); + const imageSkeleton = document.querySelector('.rounded-md'); + expect(imageSkeleton).toHaveStyle({ width: '100px', height: '200px' }); + }); + + it('applies custom className', () => { + render(); + const container = document.querySelector('.custom-class'); + expect(container).toBeInTheDocument(); + }); + + it('has accessibility attributes', () => { + render(); + const elements = document.querySelectorAll('[aria-hidden="true"]'); + expect(elements.length).toBeGreaterThan(0); + }); +}); \ No newline at end of file diff --git a/nevo_frontend/app/about/page.tsx b/nevo_frontend/app/about/page.tsx new file mode 100644 index 0000000..f5d6cc6 --- /dev/null +++ b/nevo_frontend/app/about/page.tsx @@ -0,0 +1,450 @@ +'use client'; + +import React from 'react'; +import Link from 'next/link'; +import { Skeleton } from '@/components/Skeleton'; +import { Avatar } from '@/components/Avatar'; + +interface TeamMember { + id: string; + name: string; + role: string; + bio: string; + avatarSrc?: string; + social?: { + twitter?: string; + github?: string; + linkedin?: string; + }; +} + +interface CompanyValue { + id: string; + title: string; + description: string; + icon: React.ReactNode; +} + +const TEAM_MEMBERS: TeamMember[] = [ + { + id: '1', + name: 'Alex Morgan', + role: 'Founder & CEO', + bio: 'Blockchain enthusiast and philanthropy advocate with 8+ years in Web3 development.', + social: { + twitter: 'https://twitter.com/alexmorgan', + github: 'https://github.com/alexmorgan', + }, + }, + { + id: '2', + name: 'Sam Rivera', + role: 'CTO', + bio: 'Stellar ecosystem veteran focused on scalable smart contract architecture.', + social: { + github: 'https://github.com/samrivera', + linkedin: 'https://linkedin.com/in/samrivera', + }, + }, + { + id: '3', + name: 'Jordan Lee', + role: 'Head of Product', + bio: 'Product strategist passionate about making blockchain accessible to everyone.', + social: { + twitter: 'https://twitter.com/jordanlee', + }, + }, +]; + +const COMPANY_VALUES: CompanyValue[] = [ + { + id: 'transparency', + title: 'Transparency', + description: + 'All donations are recorded on-chain with full visibility into every transaction.', + icon: ( + + ), + }, + { + id: 'security', + title: 'Security', + description: + 'Built on Stellar smart contracts with battle-tested security patterns.', + icon: ( + + ), + }, + { + id: 'community', + title: 'Community', + description: 'Empowering local communities through decentralized fundraising.', + icon: ( + + ), + }, + { + id: 'accessibility', + title: 'Accessibility', + description: + 'Low fees under $0.01 per transaction for truly inclusive donations.', + icon: ( + + ), + }, +]; + +const TESTIMONIALS = [ + { + quote: + 'Nevo has revolutionized how we collect donations. The transparency and low fees make it perfect for our mission.', + author: 'Maria Santos', + role: 'Clean Water Initiative', + }, + { + quote: + 'Finally, a platform that makes crypto donations accessible to everyone without hidden fees.', + author: 'Dr. James Chen', + role: 'Healthcare for All', + }, +]; + +export default function AboutPage() { + return ( +
+
+

+ Our Mission +

+

+ To empower anyone, anywhere to create transparent, secure, and efficient + fundraising pools on the Stellar blockchain — without intermediaries, + hidden fees, or complex technology barriers. +

+
+ +
+
+

+ About Nevo +

+

+ Nevo was founded in 2024 with a simple goal: make charitable giving + transparent, secure, and accessible on Web3. We believe that trust + comes from openness, not gatekeepers. +

+

+ Built on the Stellar blockchain, our platform leverages smart contracts + to create donation pools that are auditable, trustless, and efficient. + Every contribution is recorded on-chain, allowing anyone to verify that + funds reach their intended destination. +

+

+ Our platform is open-source and community-driven. We welcome + contributors who share our vision of a more transparent future for + charitable giving. +

+
+
+ +
+

+ Our Values +

+
+ {COMPANY_VALUES.map((value) => ( +
+
+ {value.icon} +
+

{value.title}

+

+ {value.description} +

+
+ ))} +
+
+ +
+

+ Meet the Team +

+
+ {TEAM_MEMBERS.map((member) => ( +
+ +

{member.name}

+

{member.role}

+

+ {member.bio} +

+ {member.social && ( +
+ {member.social.twitter && ( + + + + )} + {member.social.github && ( + + + + )} + {member.social.linkedin && ( + + + + )} +
+ )} +
+ ))} +
+
+ +
+

+ What They Say +

+
+ {TESTIMONIALS.map((testimonial, index) => ( +
+

+ "{testimonial.quote}" +

+
+ {testimonial.author} + + {' '} + — {testimonial.role} + +
+
+ ))} +
+
+ +
+

+ Get in Touch +

+
+

+ Have questions or want to learn more about Nevo? +

+
+ + Email Us + + + Contact Form + +
+
+
+
+ ); +} + +export function AboutPageSkeleton() { + return ( +
+
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+ {Array.from({ length: 4 }).map((_, i) => ( +
+
+
+
+
+ ))} +
+
+ +
+
+
+ {Array.from({ length: 3 }).map((_, i) => ( +
+
+
+
+
+
+
+ ))} +
+
+
+ ); +} \ No newline at end of file