Remove all obsolete authentication, settings, admin, and demo-related components and pages
- Eliminated redundant components, pages, and layouts related to authentication (`login`, `register`, `password-reset`, etc.), user settings, admin, and demos. - Simplified the frontend structure by removing unused dynamic imports, forms, and test code. - Refactored configurations and metadata imports to exclude references to removed features. - Streamlined the project for future development and improved maintainability by discarding legacy and unused code.
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Settings Index Page
|
||||
* Redirects to /settings/profile
|
||||
*/
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default function SettingsPage() {
|
||||
redirect('/settings/profile');
|
||||
}
|
||||
@@ -5,11 +5,12 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useRouter } from '@/lib/i18n/routing';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Alert } from '@/components/ui/alert';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
|
||||
// Code-split PasswordResetConfirmForm (319 lines)
|
||||
const PasswordResetConfirmForm = dynamic(
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from '@/lib/i18n/routing';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { User, Lock, Monitor, Settings as SettingsIcon } from 'lucide-react';
|
||||
|
||||
11
frontend/src/app/[locale]/(authenticated)/settings/page.tsx
Normal file
11
frontend/src/app/[locale]/(authenticated)/settings/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Settings Index Page
|
||||
* Redirects to /settings/profile
|
||||
*/
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default async function SettingsPage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await params;
|
||||
redirect(`/${locale}/settings/profile`);
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { OrganizationMembersContent } from '@/components/admin/organizations/OrganizationMembersContent';
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { OrganizationManagementContent } from '@/components/admin/organizations/OrganizationManagementContent';
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { DashboardStats } from '@/components/admin';
|
||||
import {
|
||||
UserGrowthChart,
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { UserManagementContent } from '@/components/admin/users/UserManagementContent';
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import {
|
||||
Palette,
|
||||
ShieldCheck,
|
||||
@@ -4,7 +4,7 @@
|
||||
* Access: /dev/docs
|
||||
*/
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import {
|
||||
BookOpen,
|
||||
Sparkles,
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Grid3x3 } from 'lucide-react';
|
||||
import { DevBreadcrumbs } from '@/components/dev/DevBreadcrumbs';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Palette, Layout, Ruler, FileText, BookOpen, ArrowRight, Sparkles } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Ruler } from 'lucide-react';
|
||||
import { DevBreadcrumbs } from '@/components/dev/DevBreadcrumbs';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/* istanbul ignore next - Next.js type import for metadata */
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ShieldAlert } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
88
frontend/src/app/[locale]/layout.tsx
Normal file
88
frontend/src/app/[locale]/layout.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { routing } from '@/lib/i18n/routing';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { getMessages } from 'next-intl/server';
|
||||
import '../globals.css';
|
||||
import { Providers } from '../providers';
|
||||
import { AuthProvider } from '@/lib/auth/AuthContext';
|
||||
import { AuthInitializer } from '@/components/auth';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: '--font-geist-sans',
|
||||
subsets: ['latin'],
|
||||
display: 'swap', // Prevent font from blocking render
|
||||
preload: true,
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: '--font-geist-mono',
|
||||
subsets: ['latin'],
|
||||
display: 'swap', // Prevent font from blocking render
|
||||
preload: false, // Only preload primary font
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'FastNext Template',
|
||||
description: 'FastAPI + Next.js Template',
|
||||
};
|
||||
|
||||
export default async function LocaleLayout({
|
||||
children,
|
||||
params,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ locale: string }>;
|
||||
}>) {
|
||||
// Await params in Next.js 15
|
||||
const { locale } = await params;
|
||||
|
||||
// Ensure that the incoming `locale` is valid
|
||||
if (!routing.locales.includes(locale as 'en' | 'it')) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
// Providing all messages to the client
|
||||
// side is the easiest way to get started
|
||||
const messages = await getMessages();
|
||||
|
||||
return (
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<head>
|
||||
{/* Theme initialization script - runs before React hydrates to prevent FOUC */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function() {
|
||||
try {
|
||||
const theme = localStorage.getItem('theme') || 'system';
|
||||
let resolved;
|
||||
|
||||
if (theme === 'system') {
|
||||
resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
} else {
|
||||
resolved = theme;
|
||||
}
|
||||
|
||||
document.documentElement.classList.remove('light', 'dark');
|
||||
document.documentElement.classList.add(resolved);
|
||||
} catch (e) {
|
||||
// Silently fail - theme will be set by ThemeProvider
|
||||
}
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
<AuthProvider>
|
||||
<AuthInitializer />
|
||||
<Providers>{children}</Providers>
|
||||
</AuthProvider>
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
99
frontend/src/app/[locale]/page.tsx
Executable file
99
frontend/src/app/[locale]/page.tsx
Executable file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Homepage / Landing Page
|
||||
* Main landing page for the FastNext Template project
|
||||
* Showcases features, tech stack, and provides demos for developers
|
||||
*/
|
||||
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Header } from '@/components/home/Header';
|
||||
import { HeroSection } from '@/components/home/HeroSection';
|
||||
import { ContextSection } from '@/components/home/ContextSection';
|
||||
import { AnimatedTerminal } from '@/components/home/AnimatedTerminal';
|
||||
import { FeatureGrid } from '@/components/home/FeatureGrid';
|
||||
import { DemoSection } from '@/components/home/DemoSection';
|
||||
import { StatsSection } from '@/components/home/StatsSection';
|
||||
import { TechStackSection } from '@/components/home/TechStackSection';
|
||||
import { PhilosophySection } from '@/components/home/PhilosophySection';
|
||||
import { QuickStartCode } from '@/components/home/QuickStartCode';
|
||||
import { CTASection } from '@/components/home/CTASection';
|
||||
import { DemoCredentialsModal } from '@/components/home/DemoCredentialsModal';
|
||||
|
||||
export default function Home() {
|
||||
const [demoModalOpen, setDemoModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
{/* Header Navigation */}
|
||||
<Header onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
|
||||
{/* Main Content */}
|
||||
<main>
|
||||
{/* Hero Section with CTAs */}
|
||||
<HeroSection onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
|
||||
{/* What is this template? */}
|
||||
<ContextSection />
|
||||
|
||||
{/* Animated Terminal with Quick Start */}
|
||||
<AnimatedTerminal />
|
||||
|
||||
{/* 6 Feature Cards Grid */}
|
||||
<FeatureGrid />
|
||||
|
||||
{/* Interactive Demo Cards */}
|
||||
<DemoSection />
|
||||
|
||||
{/* Statistics with Animated Counters */}
|
||||
<StatsSection />
|
||||
|
||||
{/* Tech Stack Grid */}
|
||||
<TechStackSection />
|
||||
|
||||
{/* For Developers, By Developers */}
|
||||
<PhilosophySection />
|
||||
|
||||
{/* Quick Start Code Block */}
|
||||
<QuickStartCode />
|
||||
|
||||
{/* Final CTA Section */}
|
||||
<CTASection onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t bg-muted/30">
|
||||
<div className="container mx-auto px-6 py-8">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
© {new Date().getFullYear()} FastNext Template. MIT Licensed.
|
||||
</div>
|
||||
<div className="flex items-center gap-6 text-sm text-muted-foreground">
|
||||
<Link href="/demos" className="hover:text-foreground transition-colors">
|
||||
Demo Tour
|
||||
</Link>
|
||||
<Link href="/dev" className="hover:text-foreground transition-colors">
|
||||
Design System
|
||||
</Link>
|
||||
<a
|
||||
href="https://github.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-foreground transition-colors"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<Link href="/dev/docs" className="hover:text-foreground transition-colors">
|
||||
Documentation
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* Shared Demo Credentials Modal */}
|
||||
<DemoCredentialsModal open={demoModalOpen} onClose={() => setDemoModalOpen(false)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,68 +1,15 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
import './globals.css';
|
||||
import { Providers } from './providers';
|
||||
import { AuthProvider } from '@/lib/auth/AuthContext';
|
||||
import { AuthInitializer } from '@/components/auth';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: '--font-geist-sans',
|
||||
subsets: ['latin'],
|
||||
display: 'swap', // Prevent font from blocking render
|
||||
preload: true,
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: '--font-geist-mono',
|
||||
subsets: ['latin'],
|
||||
display: 'swap', // Prevent font from blocking render
|
||||
preload: false, // Only preload primary font
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'FastNext Template',
|
||||
description: 'FastAPI + Next.js Template',
|
||||
};
|
||||
/**
|
||||
* Root Layout
|
||||
*
|
||||
* Minimal root layout that passes through to locale-specific layouts.
|
||||
* The actual HTML structure and providers are in [locale]/layout.tsx
|
||||
* to properly handle locale-specific rendering.
|
||||
*/
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
{/* Theme initialization script - runs before React hydrates to prevent FOUC */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function() {
|
||||
try {
|
||||
const theme = localStorage.getItem('theme') || 'system';
|
||||
let resolved;
|
||||
|
||||
if (theme === 'system') {
|
||||
resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
} else {
|
||||
resolved = theme;
|
||||
}
|
||||
|
||||
document.documentElement.classList.remove('light', 'dark');
|
||||
document.documentElement.classList.add(resolved);
|
||||
} catch (e) {
|
||||
// Silently fail - theme will be set by ThemeProvider
|
||||
}
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||
<AuthProvider>
|
||||
<AuthInitializer />
|
||||
<Providers>{children}</Providers>
|
||||
</AuthProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
return children;
|
||||
}
|
||||
|
||||
99
frontend/src/app/page.tsx
Executable file → Normal file
99
frontend/src/app/page.tsx
Executable file → Normal file
@@ -1,99 +1,10 @@
|
||||
/**
|
||||
* Homepage / Landing Page
|
||||
* Main landing page for the FastNext Template project
|
||||
* Showcases features, tech stack, and provides demos for developers
|
||||
* Root page - redirects to default locale
|
||||
*/
|
||||
|
||||
'use client';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Header } from '@/components/home/Header';
|
||||
import { HeroSection } from '@/components/home/HeroSection';
|
||||
import { ContextSection } from '@/components/home/ContextSection';
|
||||
import { AnimatedTerminal } from '@/components/home/AnimatedTerminal';
|
||||
import { FeatureGrid } from '@/components/home/FeatureGrid';
|
||||
import { DemoSection } from '@/components/home/DemoSection';
|
||||
import { StatsSection } from '@/components/home/StatsSection';
|
||||
import { TechStackSection } from '@/components/home/TechStackSection';
|
||||
import { PhilosophySection } from '@/components/home/PhilosophySection';
|
||||
import { QuickStartCode } from '@/components/home/QuickStartCode';
|
||||
import { CTASection } from '@/components/home/CTASection';
|
||||
import { DemoCredentialsModal } from '@/components/home/DemoCredentialsModal';
|
||||
|
||||
export default function Home() {
|
||||
const [demoModalOpen, setDemoModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
{/* Header Navigation */}
|
||||
<Header onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
|
||||
{/* Main Content */}
|
||||
<main>
|
||||
{/* Hero Section with CTAs */}
|
||||
<HeroSection onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
|
||||
{/* What is this template? */}
|
||||
<ContextSection />
|
||||
|
||||
{/* Animated Terminal with Quick Start */}
|
||||
<AnimatedTerminal />
|
||||
|
||||
{/* 6 Feature Cards Grid */}
|
||||
<FeatureGrid />
|
||||
|
||||
{/* Interactive Demo Cards */}
|
||||
<DemoSection />
|
||||
|
||||
{/* Statistics with Animated Counters */}
|
||||
<StatsSection />
|
||||
|
||||
{/* Tech Stack Grid */}
|
||||
<TechStackSection />
|
||||
|
||||
{/* For Developers, By Developers */}
|
||||
<PhilosophySection />
|
||||
|
||||
{/* Quick Start Code Block */}
|
||||
<QuickStartCode />
|
||||
|
||||
{/* Final CTA Section */}
|
||||
<CTASection onOpenDemoModal={() => setDemoModalOpen(true)} />
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t bg-muted/30">
|
||||
<div className="container mx-auto px-6 py-8">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
© {new Date().getFullYear()} FastNext Template. MIT Licensed.
|
||||
</div>
|
||||
<div className="flex items-center gap-6 text-sm text-muted-foreground">
|
||||
<Link href="/demos" className="hover:text-foreground transition-colors">
|
||||
Demo Tour
|
||||
</Link>
|
||||
<Link href="/dev" className="hover:text-foreground transition-colors">
|
||||
Design System
|
||||
</Link>
|
||||
<a
|
||||
href="https://github.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-foreground transition-colors"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<Link href="/dev/docs" className="hover:text-foreground transition-colors">
|
||||
Documentation
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* Shared Demo Credentials Modal */}
|
||||
<DemoCredentialsModal open={demoModalOpen} onClose={() => setDemoModalOpen(false)} />
|
||||
</div>
|
||||
);
|
||||
export default function RootPage() {
|
||||
// Redirect to default locale (en)
|
||||
redirect('/en');
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { usePathname } from '@/lib/i18n/routing';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
LayoutDashboard,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { usePathname } from '@/lib/i18n/routing';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
|
||||
interface BreadcrumbItem {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useRouter } from '@/lib/i18n/routing';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useRouter } from '@/lib/i18n/routing';
|
||||
import { UserPlus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useRouter } from '@/lib/i18n/routing';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAuth } from '@/lib/auth/AuthContext';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter, usePathname } from 'next/navigation';
|
||||
import { useRouter, usePathname } from '@/lib/i18n/routing';
|
||||
import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import { useMe } from '@/lib/api/hooks/useAuth';
|
||||
import { AuthLoadingSkeleton } from '@/components/layout';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { ChevronRight, Home } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { usePathname } from '@/lib/i18n/routing';
|
||||
import {
|
||||
Code2,
|
||||
Palette,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useEffect, useState, useRef } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Terminal, Play } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
|
||||
const commands = [
|
||||
{ text: '# Clone the repository', delay: 0 },
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Github, Star, Play, ArrowRight } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Copy, Check } from 'lucide-react';
|
||||
import {
|
||||
Dialog,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Play, Layers, ShieldCheck, UserCircle } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowRight, LucideIcon } from 'lucide-react';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { Menu, X, Github, Star } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowRight, Github, Play } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
|
||||
export function Footer() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Link } from '@/lib/i18n/routing';
|
||||
import { usePathname } from '@/lib/i18n/routing';
|
||||
import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import { useLogout } from '@/lib/api/hooks/useAuth';
|
||||
import {
|
||||
|
||||
@@ -9,8 +9,9 @@ const intlMiddleware = createMiddleware(routing);
|
||||
export function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
// Block access to /dev routes in production (before locale handling)
|
||||
if (pathname.startsWith('/dev')) {
|
||||
// Block access to /dev routes in production (handles both /dev and /[locale]/dev)
|
||||
// Match: /dev, /en/dev, /it/dev, etc.
|
||||
if (pathname === '/dev' || pathname.match(/^\/[a-z]{2}\/dev($|\/)/)) {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
if (isProduction) {
|
||||
|
||||
Reference in New Issue
Block a user