create-next-pro-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/CODE_OF_CONDUCT.md +33 -0
  3. package/CONTRIBUTING.md +44 -0
  4. package/FONCTIONALITY.md +25 -0
  5. package/README.md +292 -0
  6. package/bin.ts +2 -0
  7. package/bun.lock +27 -0
  8. package/create-next-pro-completion.sh +36 -0
  9. package/install.sh +18 -0
  10. package/package.json +32 -0
  11. package/public/logo.svg +76 -0
  12. package/src/index.ts +511 -0
  13. package/src/scaffold-dev.ts +89 -0
  14. package/src/scaffold.ts +70 -0
  15. package/templates/Component/Component.tsx +13 -0
  16. package/templates/Component/component.json +4 -0
  17. package/templates/Page/default.tsx +0 -0
  18. package/templates/Page/error.tsx +38 -0
  19. package/templates/Page/global-error.tsx +0 -0
  20. package/templates/Page/layout.tsx +0 -0
  21. package/templates/Page/loading.tsx +17 -0
  22. package/templates/Page/not-found.tsx +0 -0
  23. package/templates/Page/page-ui.tsx +22 -0
  24. package/templates/Page/page.json +4 -0
  25. package/templates/Page/page.tsx +24 -0
  26. package/templates/Page/route.ts +0 -0
  27. package/templates/Page/template.tsx +0 -0
  28. package/templates/Projects/default/README.md +36 -0
  29. package/templates/Projects/default/eslint.config.mjs +16 -0
  30. package/templates/Projects/default/messages/en/_global_ui.json +30 -0
  31. package/templates/Projects/default/messages/en/_home.json +4 -0
  32. package/templates/Projects/default/messages/en/dashboard.json +14 -0
  33. package/templates/Projects/default/messages/en/login.json +7 -0
  34. package/templates/Projects/default/messages/en/register.json +7 -0
  35. package/templates/Projects/default/messages/en/settings.json +4 -0
  36. package/templates/Projects/default/messages/en/user_info.json +4 -0
  37. package/templates/Projects/default/messages/en.ts +4 -0
  38. package/templates/Projects/default/messages/fr/_global_ui.json +30 -0
  39. package/templates/Projects/default/messages/fr/_home.json +4 -0
  40. package/templates/Projects/default/messages/fr/dashboard.json +14 -0
  41. package/templates/Projects/default/messages/fr/login.json +7 -0
  42. package/templates/Projects/default/messages/fr/register.json +7 -0
  43. package/templates/Projects/default/messages/fr/settings.json +4 -0
  44. package/templates/Projects/default/messages/fr/user_info.json +4 -0
  45. package/templates/Projects/default/messages/fr.ts +4 -0
  46. package/templates/Projects/default/messages/getMergedMessages.ts +31 -0
  47. package/templates/Projects/default/middleware.ts +11 -0
  48. package/templates/Projects/default/next.config.ts +12 -0
  49. package/templates/Projects/default/package.json +32 -0
  50. package/templates/Projects/default/postcss.config.mjs +5 -0
  51. package/templates/Projects/default/public/cnp-logo.ico +0 -0
  52. package/templates/Projects/default/public/cnp-logo.png +0 -0
  53. package/templates/Projects/default/public/cnp-logo.svg +76 -0
  54. package/templates/Projects/default/public/file.svg +1 -0
  55. package/templates/Projects/default/public/globe.svg +1 -0
  56. package/templates/Projects/default/public/next.svg +1 -0
  57. package/templates/Projects/default/public/vercel.svg +1 -0
  58. package/templates/Projects/default/public/window.svg +1 -0
  59. package/templates/Projects/default/src/app/[locale]/(public)/_home/loading.tsx +1 -0
  60. package/templates/Projects/default/src/app/[locale]/(public)/_home/page.tsx +16 -0
  61. package/templates/Projects/default/src/app/[locale]/(public)/layout.tsx +11 -0
  62. package/templates/Projects/default/src/app/[locale]/(public)/login/page.tsx +19 -0
  63. package/templates/Projects/default/src/app/[locale]/(public)/register/page.tsx +23 -0
  64. package/templates/Projects/default/src/app/[locale]/(user)/dashboard/error.tsx +38 -0
  65. package/templates/Projects/default/src/app/[locale]/(user)/dashboard/loading.tsx +17 -0
  66. package/templates/Projects/default/src/app/[locale]/(user)/dashboard/page.tsx +12 -0
  67. package/templates/Projects/default/src/app/[locale]/(user)/layout.tsx +12 -0
  68. package/templates/Projects/default/src/app/[locale]/(user)/settings/loading.tsx +17 -0
  69. package/templates/Projects/default/src/app/[locale]/(user)/settings/page.tsx +12 -0
  70. package/templates/Projects/default/src/app/[locale]/(user)/user_info/loading.tsx +17 -0
  71. package/templates/Projects/default/src/app/[locale]/(user)/user_info/page.tsx +12 -0
  72. package/templates/Projects/default/src/app/[locale]/layout.tsx +32 -0
  73. package/templates/Projects/default/src/app/[locale]/loading.tsx +17 -0
  74. package/templates/Projects/default/src/app/[locale]/not-found.tsx +22 -0
  75. package/templates/Projects/default/src/app/[locale]/page.tsx +116 -0
  76. package/templates/Projects/default/src/app/api/auth/[...nextauth]/route.ts +81 -0
  77. package/templates/Projects/default/src/app/api/auth/[...nextauth].ts +0 -0
  78. package/templates/Projects/default/src/app/api/auth/post-login/route.ts +27 -0
  79. package/templates/Projects/default/src/app/api/me/route.ts +15 -0
  80. package/templates/Projects/default/src/app/favicon.ico +0 -0
  81. package/templates/Projects/default/src/app/layout.tsx +11 -0
  82. package/templates/Projects/default/src/app/not-found.tsx +17 -0
  83. package/templates/Projects/default/src/app/page.tsx +6 -0
  84. package/templates/Projects/default/src/app/sitemap.ts +27 -0
  85. package/templates/Projects/default/src/app/styles/globals.css +26 -0
  86. package/templates/Projects/default/src/app/ui/dashboard/MainDashboard.tsx +21 -0
  87. package/templates/Projects/default/src/app/ui/dashboard/StatsCard.tsx +14 -0
  88. package/templates/Projects/default/src/app/ui/dashboard/WelcomeCard.tsx +10 -0
  89. package/templates/Projects/default/src/auth.config.ts +0 -0
  90. package/templates/Projects/default/src/config.ts +4 -0
  91. package/templates/Projects/default/src/lib/auth/isConnected.ts +16 -0
  92. package/templates/Projects/default/src/lib/i18n/navigation.ts +19 -0
  93. package/templates/Projects/default/src/lib/i18n/request.ts +31 -0
  94. package/templates/Projects/default/src/lib/i18n/routing.ts +20 -0
  95. package/templates/Projects/default/src/ui/_global/BackButton.tsx +15 -0
  96. package/templates/Projects/default/src/ui/_global/GlobalHeader.tsx +34 -0
  97. package/templates/Projects/default/src/ui/_global/GlobalMain.tsx +15 -0
  98. package/templates/Projects/default/src/ui/_global/LocaleSwitcher.tsx +38 -0
  99. package/templates/Projects/default/src/ui/_global/PublicNav.tsx +30 -0
  100. package/templates/Projects/default/src/ui/_global/UserNav.tsx +32 -0
  101. package/templates/Projects/default/src/ui/dashboard/StatsCard.tsx +14 -0
  102. package/templates/Projects/default/src/ui/dashboard/WelcomeCard.tsx +10 -0
  103. package/templates/Projects/default/src/ui/dashboard/page.tsx +22 -0
  104. package/templates/Projects/default/tailwind.config.ts +1 -0
  105. package/templates/Projects/default/tsconfig.json +34 -0
  106. package/tsconfig.json +27 -0
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { useTranslations } from "next-intl";
3
+ import { signIn } from "next-auth/react";
4
+ import BackButton from "@/ui/_global/BackButton";
5
+
6
+ export default function RegisterPage() {
7
+ const t = useTranslations("register");
8
+ return (
9
+ <main className="py-8 px-4 max-w-md mx-auto">
10
+ <div className="flex items-center justify-between mb-6">
11
+ <h1 className="text-2xl font-bold">{t("title")}</h1>
12
+ <BackButton />
13
+ </div>
14
+ <p className="text-muted mb-6">{t("description")}</p>
15
+ <button
16
+ onClick={() => signIn()}
17
+ className="w-full py-2 px-4 rounded bg-blue-600 text-white font-semibold hover:bg-blue-700 transition"
18
+ >
19
+ {t("register_with_google")}
20
+ </button>
21
+ </main>
22
+ );
23
+ }
@@ -0,0 +1,38 @@
1
+ // app/[locale]/error.tsx
2
+ "use client"; // Error boundaries must be Client Components
3
+
4
+ import { useEffect } from "react";
5
+
6
+ export default function Error({
7
+ error,
8
+ reset,
9
+ }: {
10
+ error: Error & { digest?: string };
11
+ reset: () => void;
12
+ }) {
13
+ useEffect(() => {
14
+ // Log the error to an error reporting service
15
+ console.error(error);
16
+ }, [error]);
17
+
18
+ return (
19
+ <div>
20
+ <h2>Something went wrong!</h2>
21
+ <button
22
+ onClick={
23
+ // Attempt to recover by trying to re-render the segment
24
+ () => reset()
25
+ }
26
+ >
27
+ Try again
28
+ </button>
29
+ </div>
30
+ );
31
+ }
32
+ // This page is used to handle errors in the application
33
+ // You can customize this page to display a user-friendly error message
34
+ // or redirect to a different page if needed
35
+ // This is part of the Next.js app directory structure and will be automatically used by Next.js
36
+ // when an error occurs in the application
37
+ // Make sure to handle errors gracefully to improve user experience
38
+ // You can also log errors or send them to an error tracking service
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading dashboard...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,12 @@
1
+ import Dashboard from "@/ui/dashboard/page";
2
+
3
+ export default function DashboardPage() {
4
+ return <Dashboard />;
5
+ }
6
+ // This page is the main entry point for the dashboard
7
+ // It uses the `useTranslations` hook to fetch localized strings
8
+ // The `t` function is used to get the translated strings for the dashboard
9
+ // You can add more components or logic here to build your dashboard
10
+ // This is part of the Next.js app directory structure
11
+ // It will be automatically rendered when the user navigates to the dashboard
12
+ // Make sure to define the translations in your locale files
@@ -0,0 +1,12 @@
1
+ // app/[locale]/(user)/layout.tsx
2
+
3
+ import UserNav from "@/ui/_global/UserNav";
4
+ import LocaleSwitcher from "@/ui/_global/LocaleSwitcher";
5
+
6
+ export default function UserLayout({
7
+ children,
8
+ }: {
9
+ children: React.ReactNode;
10
+ }) {
11
+ return children;
12
+ }
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading user info...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useTranslations } from "next-intl";
3
+
4
+ export default function UserInfoPage() {
5
+ const t = useTranslations("settings");
6
+ return (
7
+ <main className="py-8 px-4 max-w-3xl mx-auto">
8
+ <h1 className="text-2xl font-bold">{t("title")}</h1>
9
+ <p className="text-muted mt-2">{t("description")}</p>
10
+ </main>
11
+ );
12
+ }
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading user info...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useTranslations } from "next-intl";
3
+
4
+ export default function UserInfoPage() {
5
+ const t = useTranslations("user_info");
6
+ return (
7
+ <main className="py-8 px-4 max-w-3xl mx-auto">
8
+ <h1 className="text-2xl font-bold">{t("title")}</h1>
9
+ <p className="text-muted mt-2">{t("description")}</p>
10
+ </main>
11
+ );
12
+ }
@@ -0,0 +1,32 @@
1
+ // app/[locale]/layout.tsx
2
+ import { setRequestLocale } from "next-intl/server";
3
+ import { NextIntlClientProvider, hasLocale, Locale } from "next-intl";
4
+ import React from "react";
5
+ import "@/app/styles/globals.css"; // Import global styles
6
+ import GlobalHeader from "@/ui/_global/GlobalHeader";
7
+ import GlobalMain from "@/ui/_global/GlobalMain";
8
+ import { isConnected } from "@/lib/auth/isConnected";
9
+
10
+ export default async function LocaleLayout({
11
+ children,
12
+ params,
13
+ }: {
14
+ children: React.ReactNode;
15
+ params: Promise<{ locale: string }>;
16
+ }) {
17
+ const { locale } = await params;
18
+ setRequestLocale(locale);
19
+
20
+ const isConnectedValue = await isConnected();
21
+
22
+ return (
23
+ <html lang={locale}>
24
+ <body>
25
+ <NextIntlClientProvider>
26
+ <GlobalHeader isConnected={isConnectedValue} />
27
+ <GlobalMain>{children}</GlobalMain>
28
+ </NextIntlClientProvider>
29
+ </body>
30
+ </html>
31
+ );
32
+ }
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading ROOT...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,22 @@
1
+ // app/[locale]/not-found.tsx
2
+ import { Link } from "@/lib/i18n/navigation";
3
+
4
+ export default function NotFound() {
5
+ return (
6
+ <div>
7
+ <h2>Not Found</h2>
8
+ <p>Could not find requested resource</p>
9
+ <Link href="/">Return Home</Link>
10
+ </div>
11
+ );
12
+ }
13
+ // This page is used to handle 404 errors in the application
14
+ // You can customize this page to display a user-friendly error message
15
+ // or redirect to a different page if needed
16
+ // This is part of the Next.js app directory structure and will be automatically used by Next.js
17
+ // when a requested page is not found
18
+ // Make sure to handle 404 errors gracefully to improve user experience
19
+ // You can also log errors or send them to an error tracking service
20
+ // This component can be styled with CSS or Tailwind CSS to match your application's design
21
+ // You can also add additional links or actions for the user to take, such as searching or navigating to other parts of the site
22
+ // This component is lightweight and does not block the main thread
@@ -0,0 +1,116 @@
1
+ import React from "react";
2
+ import Image from "next/image";
3
+ import HomePage from "@/app/[locale]/(public)/_home/page";
4
+ import DashboardPage from "@/app/[locale]/(user)/dashboard/page";
5
+ import PublicNav from "@/ui/_global/PublicNav";
6
+ import UserNav from "@/ui/_global/UserNav";
7
+ import LocaleSwitcher from "@/ui/_global/LocaleSwitcher";
8
+ import { cookies } from "next/headers";
9
+ import { verify } from "jsonwebtoken";
10
+
11
+ export default async function FallbackPage() {
12
+ let isConnected = false;
13
+ const cookieStore = await cookies();
14
+ const appToken = cookieStore.get("app_token")?.value;
15
+ if (appToken) {
16
+ try {
17
+ verify(appToken, process.env.APP_JWT_SECRET!);
18
+ isConnected = true;
19
+ } catch {
20
+ isConnected = false;
21
+ }
22
+ }
23
+
24
+ return (
25
+ <HomePage />
26
+ /* <main className="min-h-screen bg-neutral-50 font-sans text-gray-900">
27
+ <header className="sticky top-0 z-30 w-full border-b bg-white/80 backdrop-blur supports-[backdrop-filter]:bg-white/60 shadow-sm">
28
+ <div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-6">
29
+ <div className="flex items-center gap-3">
30
+ <Image
31
+ src="/cnp-logo.svg"
32
+ alt="Logo"
33
+ width={63}
34
+ height={63}
35
+ className="mr-2"
36
+ />
37
+ <span className="text-lg font-semibold tracking-tight select-none">
38
+ Create Next Pro
39
+ </span>
40
+ </div>
41
+ <nav className="flex items-center gap-4">
42
+ {isConnected ? <UserNav /> : <PublicNav />}
43
+ <LocaleSwitcher />
44
+ </nav>
45
+ </div>
46
+ </header>
47
+
48
+ <section className="mx-auto w-full max-w-3xl py-16 px-6">
49
+ {isConnected ? <DashboardPage /> : <HomePage />}
50
+ </section>
51
+ </main> */
52
+ );
53
+ }
54
+
55
+ // Design inspiré de nextjs.org avec Tailwind CSS.
56
+
57
+ // import React from "react";
58
+ // import HomePage from "@/app/[locale]/(public)/_home/page";
59
+ // import DashboardPage from "@/app/[locale]/(user)/dashboard/page";
60
+ // import PublicNav from "@/ui/_global/PublicNav";
61
+ // import UserNav from "@/ui/_global/UserNav";
62
+ // import LocaleSwitcher from "@/ui/_global/LocaleSwitcher";
63
+
64
+ // export default async function FallbackPage({
65
+ // params,
66
+ // }: {
67
+ // params: Promise<{ locale: string }>;
68
+ // }) {
69
+ // // TODO: Remplacer par la logique réelle d'authentification (next-auth)
70
+ // const isConnected = false;
71
+ // const { locale } = await params;
72
+
73
+ // return (
74
+ // <main className="min-h-screen bg-neutral-50 font-sans text-gray-900">
75
+ // {/* Header sticky façon nextjs.org */}
76
+ // <header className="sticky top-0 z-30 w-full border-b bg-white/80 backdrop-blur supports-[backdrop-filter]:bg-white/60 shadow-sm">
77
+ // <div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-6">
78
+ // <div className="flex items-center gap-3">
79
+ // {/* Logo Next.js SVG */}
80
+ // <svg
81
+ // width="32"
82
+ // height="32"
83
+ // viewBox="0 0 32 32"
84
+ // fill="none"
85
+ // xmlns="http://www.w3.org/2000/svg"
86
+ // className="mr-2"
87
+ // >
88
+ // <rect width="32" height="32" rx="16" fill="#000" />
89
+ // <path
90
+ // d="M16.018 29.917c7.66 0 13.899-6.238 13.899-13.899 0-7.66-6.239-13.899-13.899-13.899-7.66 0-13.899 6.239-13.899 13.899 0 7.661 6.239 13.899 13.899 13.899Z"
91
+ // fill="#fff"
92
+ // />
93
+ // <path
94
+ // d="M23.635 22.295 12.7 10.36h-1.68v11.28h1.44v-9.12l10.08 10.08 1.095-1.095ZM19.36 21.64h1.44V10.36h-1.44v11.28Z"
95
+ // fill="#000"
96
+ // />
97
+ // </svg>
98
+ // <span className="text-lg font-semibold tracking-tight select-none">
99
+ // Create Next Pro
100
+ // </span>
101
+ // </div>
102
+ // <nav className="flex items-center gap-4">
103
+ // {isConnected ? <UserNav /> : <PublicNav />}
104
+ // <LocaleSwitcher />
105
+ // </nav>
106
+ // </div>
107
+ // </header>
108
+ // {/* Main content */}
109
+ // <section className="mx-auto w-full max-w-3xl py-16 px-6">
110
+ // {isConnected ? <DashboardPage /> : <HomePage />}
111
+ // </section>
112
+ // </main>
113
+ // );
114
+ // }
115
+
116
+ // // Design inspiré de nextjs.org avec Tailwind CSS.
@@ -0,0 +1,81 @@
1
+ import { sign } from "jsonwebtoken";
2
+ import NextAuth from "next-auth";
3
+ //import { authOptions } from "@/auth.config";
4
+ import type {
5
+ NextAuthOptions,
6
+ Session,
7
+ User,
8
+ Account,
9
+ Profile,
10
+ } from "next-auth";
11
+ import GoogleProvider from "next-auth/providers/google";
12
+ import type { JWT } from "next-auth/jwt";
13
+ import { getToken } from "next-auth/jwt";
14
+ import { NextRequest, NextResponse } from "next/server";
15
+
16
+ const authOptions: NextAuthOptions = {
17
+ providers: [
18
+ GoogleProvider({
19
+ clientId: process.env.GOOGLE_CLIENT_ID!,
20
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
21
+ }),
22
+ ],
23
+ callbacks: {
24
+ async jwt({ token, user }: { token: JWT; user?: User }) {
25
+ if (user) {
26
+ token.id = user.id;
27
+ token.email = user.email;
28
+ token.name = user.name;
29
+ }
30
+ console.log("JWT Callback:", token);
31
+ // On ne met rien dans le token NextAuth
32
+ // Le token JWT applicatif est géré dans le middleware
33
+ // et dans le callback de la route d'authentification
34
+ // pour éviter de le stocker dans la session NextAuth
35
+ // et de le renvoyer au client.
36
+ // Il est uniquement utilisé côté serveur pour vérifier l'authentification.
37
+ // On peut ajouter des données supplémentaires si nécessaire
38
+ // mais pour l'instant, on garde le token minimaliste.
39
+ // Exemple d'ajout de données :
40
+ // token.customData = "some data";
41
+ return token;
42
+ },
43
+ async session({ session, token }: { session: Session; token: JWT }) {
44
+ // On ne met rien dans la session NextAuth
45
+ return session;
46
+ },
47
+ async signIn({
48
+ user,
49
+ account,
50
+ profile,
51
+ email,
52
+ credentials,
53
+ }: {
54
+ user: User;
55
+ account: Account | null;
56
+ profile?: Profile;
57
+ email?: string | { verificationRequest?: boolean };
58
+ credentials?: Record<string, unknown>;
59
+ }) {
60
+ return true;
61
+ },
62
+ async redirect({ url, baseUrl }: { url: string; baseUrl: string }) {
63
+ // Après login, redirige vers l'endpoint qui pose le cookie JWT applicatif
64
+ // console.log("Before Redirect Callback :", { url: url, baseUrl: baseUrl });
65
+ const customCallbackRoute = "/api/auth/post-login";
66
+ /* if (url.startsWith(baseUrl)) {
67
+ console.log("Redirecting to post-login endpoint");
68
+ return "/api/auth/post-login";
69
+ } */
70
+ // console.log("Redirecting to base URL + customCallbackRoute");
71
+ return baseUrl + customCallbackRoute;
72
+ },
73
+ },
74
+ // Ajoute ici d'autres options/callbacks si besoin
75
+ };
76
+
77
+ // Suppression de customJwtCookie : la pose du cookie se fait dans /api/auth/post-login
78
+
79
+ const handler = NextAuth(authOptions);
80
+
81
+ export { handler as GET, handler as POST };
@@ -0,0 +1,27 @@
1
+ import { getToken } from "next-auth/jwt";
2
+ import { sign } from "jsonwebtoken";
3
+ import { NextResponse, NextRequest } from "next/server";
4
+ import { redirect } from "@/lib/i18n/navigation";
5
+ // import { NextURL } from "next/dist/server/web/next-url";
6
+
7
+ export async function GET(req: NextRequest) {
8
+ const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
9
+ if (token) {
10
+ const appJwt = sign(
11
+ { id: token.id, email: token.email, name: token.name },
12
+ process.env.APP_JWT_SECRET!,
13
+ { expiresIn: "7d" }
14
+ );
15
+ const res = NextResponse.redirect(req.nextUrl.origin + "/");
16
+ res.cookies.set("app_token", appJwt, {
17
+ httpOnly: true,
18
+ secure: process.env.NODE_ENV === "production",
19
+ sameSite: "strict",
20
+ path: "/",
21
+ maxAge: 60 * 60 * 24 * 7,
22
+ });
23
+ return res;
24
+ }
25
+ // Si pas de token, redirige vers login
26
+ return redirect({ href: "/login", locale: "en" });
27
+ }
@@ -0,0 +1,15 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { verify } from "jsonwebtoken";
3
+
4
+ export async function GET(req: NextRequest) {
5
+ const cookie = req.cookies.get("app_token")?.value;
6
+ if (!cookie) {
7
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
8
+ }
9
+ try {
10
+ const user = verify(cookie, process.env.APP_JWT_SECRET!);
11
+ return NextResponse.json({ user });
12
+ } catch {
13
+ return NextResponse.json({ error: "Invalid token" }, { status: 401 });
14
+ }
15
+ }
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from "react";
2
+
3
+ type Props = {
4
+ children: ReactNode;
5
+ };
6
+
7
+ // Since we have a `not-found.tsx` page on the root, a layout file
8
+ // is required, even if it's just passing children through.
9
+ export default function RootLayout({ children }: Props) {
10
+ return children;
11
+ }
@@ -0,0 +1,17 @@
1
+ "use client";
2
+
3
+ import Error from "next/error";
4
+
5
+ // This page renders when a route like `/unknown.txt` is requested.
6
+ // In this case, the layout at `app/[locale]/layout.tsx` receives
7
+ // an invalid value as the `[locale]` param and calls `notFound()`.
8
+
9
+ export default function GlobalNotFound() {
10
+ return (
11
+ <html lang="en">
12
+ <body>
13
+ <Error statusCode={404} />;
14
+ </body>
15
+ </html>
16
+ );
17
+ }
@@ -0,0 +1,6 @@
1
+ import { redirect } from "next/navigation";
2
+
3
+ // This page only renders when the app is built statically (output: 'export')
4
+ export default function RootPage() {
5
+ redirect("/en");
6
+ }
@@ -0,0 +1,27 @@
1
+ import { MetadataRoute } from "next";
2
+ import { Locale } from "next-intl";
3
+ import { host } from "@/config";
4
+ import { routing } from "@/lib/i18n/routing";
5
+ import { getPathname } from "@/lib/i18n/navigation";
6
+
7
+ export default function sitemap(): MetadataRoute.Sitemap {
8
+ return [...getEntries("/"), ...getEntries("/pathnames")];
9
+ }
10
+
11
+ type Href = Parameters<typeof getPathname>[0]["href"];
12
+
13
+ function getEntries(href: Href) {
14
+ return routing.locales.map((locale) => ({
15
+ url: getUrl(href, locale),
16
+ alternates: {
17
+ languages: Object.fromEntries(
18
+ routing.locales.map((cur) => [cur, getUrl(href, cur)])
19
+ ),
20
+ },
21
+ }));
22
+ }
23
+
24
+ function getUrl(href: Href, locale: Locale) {
25
+ const pathname = getPathname({ locale, href });
26
+ return host + pathname;
27
+ }
@@ -0,0 +1,26 @@
1
+ @import "tailwindcss";
2
+
3
+ :root {
4
+ --background: #ffffff;
5
+ --foreground: #171717;
6
+ }
7
+
8
+ @theme inline {
9
+ --color-background: var(--background);
10
+ --color-foreground: var(--foreground);
11
+ --font-sans: var(--font-geist-sans);
12
+ --font-mono: var(--font-geist-mono);
13
+ }
14
+
15
+ @media (prefers-color-scheme: dark) {
16
+ :root {
17
+ --background: #0a0a0a;
18
+ --foreground: #ededed;
19
+ }
20
+ }
21
+
22
+ body {
23
+ background: var(--background);
24
+ color: var(--foreground);
25
+ font-family: Arial, Helvetica, sans-serif;
26
+ }
@@ -0,0 +1,21 @@
1
+ import { useTranslations } from "next-intl";
2
+ import BackButton from "@/ui/_global/BackButton";
3
+ import WelcomeCard from "@/ui/dashboard/WelcomeCard";
4
+ import StatsCard from "@/ui/dashboard/StatsCard";
5
+
6
+ export default function DashboardPage() {
7
+ const t = useTranslations("dashboard");
8
+ return (
9
+ <main className="py-8 px-4 max-w-3xl mx-auto">
10
+ <div className="flex items-center justify-between mb-6">
11
+ <h1 className="text-2xl font-bold">{t("title")}</h1>
12
+ <BackButton />
13
+ </div>
14
+ <p className="text-muted mb-8">{t("description")}</p>
15
+ <section className="grid grid-cols-1 md:grid-cols-2 gap-6">
16
+ <WelcomeCard t={t} />
17
+ <StatsCard t={t} />
18
+ </section>
19
+ </main>
20
+ );
21
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+
3
+ export default function StatsCard({ t }: { t: (key: string) => string }) {
4
+ return (
5
+ <div className="rounded border bg-white p-6 shadow-sm">
6
+ <h2 className="text-lg font-semibold mb-2">Statistiques</h2>
7
+ <ul className="text-sm text-gray-600 space-y-1">
8
+ <li>• {t("widgets.stats.views")}: 123</li>
9
+ <li>• {t("widgets.stats.likes")}: 45</li>
10
+ <li>• {t("widgets.stats.comments")}: 7</li>
11
+ </ul>
12
+ </div>
13
+ );
14
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+
3
+ export default function WelcomeCard({ t }: { t: (key: string) => string }) {
4
+ return (
5
+ <div className="rounded border bg-white p-6 shadow-sm">
6
+ <h2 className="text-lg font-semibold mb-2">{t("widgets.welcome")}</h2>
7
+ <p className="text-gray-600">{t("widgets.description")}</p>
8
+ </div>
9
+ );
10
+ }
File without changes
@@ -0,0 +1,4 @@
1
+ export const port = process.env.PORT || 3000;
2
+ export const host = process.env.PROJECT_PRODUCTION_URL
3
+ ? `https://${process.env.PROJECT_PRODUCTION_URL}`
4
+ : `http://localhost:${port}`;