Copy overhaul + qr designs

This commit is contained in:
2026-07-27 17:54:59 +02:00
parent 033bc7e29d
commit 70d97aa970
144 changed files with 23107 additions and 1699 deletions

View File

@@ -44,10 +44,10 @@ export default function ForgotPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Check Your Email</h1>
<p className="text-gray-600 mt-2">We've sent you a password reset link</p>
</div>
@@ -98,10 +98,10 @@ export default function ForgotPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Forgot Password?</h1>
<p className="text-gray-600 mt-2">No worries, we'll send you reset instructions</p>
</div>

View File

@@ -5,10 +5,10 @@ import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
import { Card, CardContent } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { useTranslation } from '@/hooks/useTranslation';
import { useCsrf } from '@/hooks/useCsrf';
import { appendRedirectParam, sanitizeRedirectPath } from '@/lib/auth-flow';
import { Button } from '@/components/ui/Button';
import { useTranslation } from '@/hooks/useTranslation';
import { useCsrf } from '@/hooks/useCsrf';
import { appendRedirectParam, sanitizeRedirectPath } from '@/lib/auth-flow';
type LoginClientProps = {
showPageHeading?: boolean;
@@ -21,10 +21,10 @@ export default function LoginClient({ showPageHeading = true }: LoginClientProps
const { fetchWithCsrf, loading: csrfLoading } = useCsrf();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [showPassword, setShowPassword] = useState(false);
const redirectTarget = sanitizeRedirectPath(searchParams.get('redirect'));
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [showPassword, setShowPassword] = useState(false);
const redirectTarget = sanitizeRedirectPath(searchParams.get('redirect'));
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -59,12 +59,12 @@ export default function LoginClient({ showPageHeading = true }: LoginClientProps
console.error('PostHog tracking error:', error);
}
// Check for redirect parameter
const redirectUrl = data.needsOnboarding
? appendRedirectParam('/onboarding', redirectTarget)
: (redirectTarget || '/dashboard');
router.push(redirectUrl);
router.refresh();
// Check for redirect parameter
const redirectUrl = data.needsOnboarding
? appendRedirectParam('/onboarding', redirectTarget)
: (redirectTarget || '/dashboard');
router.push(redirectUrl);
router.refresh();
} else {
setError(data.error || 'Invalid email or password');
}
@@ -75,17 +75,17 @@ export default function LoginClient({ showPageHeading = true }: LoginClientProps
}
};
const handleGoogleSignIn = () => {
// Redirect to Google OAuth API route
window.location.href = appendRedirectParam('/api/auth/google', redirectTarget);
};
const handleGoogleSignIn = () => {
// Redirect to Google OAuth API route
window.location.href = appendRedirectParam('/api/auth/google', redirectTarget);
};
return (
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
{showPageHeading ? (
@@ -203,9 +203,9 @@ export default function LoginClient({ showPageHeading = true }: LoginClientProps
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Don't have an account?{' '}
<Link href={appendRedirectParam('/signup', redirectTarget)} className="text-primary-600 hover:text-primary-700 font-medium">
Sign up
</Link>
<Link href={appendRedirectParam('/signup', redirectTarget)} className="text-primary-600 hover:text-primary-700 font-medium">
Sign up
</Link>
</p>
</div>
</CardContent>

View File

@@ -2,7 +2,7 @@ import type { Metadata } from 'next';
import LoginClient from './LoginClient';
export const metadata: Metadata = {
title: 'QR Master Smart QR Generator & Analytics',
title: 'QR Master - Smart QR Generator & Analytics',
description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics. Free advanced features, bulk generation, and custom branding available.',
robots: {
index: false,
@@ -10,11 +10,11 @@ export const metadata: Metadata = {
},
};
export default function LoginPage() {
return (
<main>
<h1 className="sr-only">Login to QR Master</h1>
<LoginClient showPageHeading={false} />
</main>
);
}
export default function LoginPage() {
return (
<main>
<h1 className="sr-only">Login to QR Master</h1>
<LoginClient showPageHeading={false} />
</main>
);
}

View File

@@ -77,10 +77,10 @@ export default function ResetPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Password Reset Successful</h1>
<p className="text-gray-600 mt-2">Your password has been updated</p>
</div>
@@ -119,10 +119,10 @@ export default function ResetPasswordPage() {
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Reset Your Password</h1>
<p className="text-gray-600 mt-2">Enter your new password below</p>
</div>

View File

@@ -1,29 +1,29 @@
'use client';
import React, { useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { useTranslation } from '@/hooks/useTranslation';
import { useCsrf } from '@/hooks/useCsrf';
import { appendRedirectParam, sanitizeRedirectPath } from '@/lib/auth-flow';
export default function SignupClient() {
const router = useRouter();
const searchParams = useSearchParams();
const { t } = useTranslation();
const { fetchWithCsrf } = useCsrf();
import React, { useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { useTranslation } from '@/hooks/useTranslation';
import { useCsrf } from '@/hooks/useCsrf';
import { appendRedirectParam, sanitizeRedirectPath } from '@/lib/auth-flow';
export default function SignupClient() {
const router = useRouter();
const searchParams = useSearchParams();
const { t } = useTranslation();
const { fetchWithCsrf } = useCsrf();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const redirectTarget = sanitizeRedirectPath(searchParams.get('redirect'));
const [error, setError] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const redirectTarget = sanitizeRedirectPath(searchParams.get('redirect'));
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -71,9 +71,9 @@ export default function SignupClient() {
console.error('PostHog tracking error:', error);
}
// Redirect to onboarding
router.push(appendRedirectParam('/onboarding', redirectTarget));
router.refresh();
// Redirect to onboarding
router.push(appendRedirectParam('/onboarding', redirectTarget));
router.refresh();
} else {
setError(data.error || 'Failed to create account');
}
@@ -84,17 +84,17 @@ export default function SignupClient() {
}
};
const handleGoogleSignIn = () => {
// Redirect to Google OAuth API route
window.location.href = appendRedirectParam('/api/auth/google', redirectTarget);
};
const handleGoogleSignIn = () => {
// Redirect to Google OAuth API route
window.location.href = appendRedirectParam('/api/auth/google', redirectTarget);
};
return (
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<Link href="/" className="inline-flex items-center space-x-2 mb-6">
<img src="/favicon1.png" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<img src="/logo.svg" alt="QR Master" className="w-10 h-10 rounded-full object-cover" />
<span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Create Account</h1>
@@ -237,11 +237,11 @@ export default function SignupClient() {
</form>
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Already have an account?{' '}
<Link href={appendRedirectParam('/login', redirectTarget)} className="text-primary-600 hover:text-primary-700 font-medium">
Sign in
</Link>
<p className="text-sm text-gray-600">
Already have an account?{' '}
<Link href={appendRedirectParam('/login', redirectTarget)} className="text-primary-600 hover:text-primary-700 font-medium">
Sign in
</Link>
</p>
</div>
</CardContent>