feat: convert to nextjs

This commit is contained in:
2024-12-07 07:45:24 +01:00
parent b248ee80ee
commit 633b8ee207
52 changed files with 4121 additions and 982 deletions

28
app/api/consumer/route.ts Normal file
View File

@@ -0,0 +1,28 @@
import { NextResponse } from 'next/server';
import { generate } from '@utils/consumer/store';
import { rateLimiter } from '@utils/rateLimiter';
export async function POST() {
const rateLimit = await rateLimiter();
if (rateLimit) {
return NextResponse.json(
{ error: 'Rate limit exceeded.' },
{ status: 429 }
);
}
try {
const data = await generate();
return NextResponse.json({
id: data.id,
consumer: data.consumer
});
} catch (error) {
console.error('Error generating consumer:', error);
return NextResponse.json(
{ error: 'Failed to generate consumer' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,38 @@
import { generate } from '@purchases/store';
import { purchasesRequestSchema } from '@purchases/types';
import { rateLimiter } from '@utils/rateLimiter';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const rateLimit = await rateLimiter();
if (rateLimit) {
return NextResponse.json(
{ error: 'Rate limit exceeded.' },
{ status: 429 }
);
}
try {
const body = await request.json();
const result = purchasesRequestSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: result.error.issues[0].message },
{ status: 400 }
);
}
const { id, consumer } = result.data;
const purchaseList = await generate(id, consumer, new Date());
return NextResponse.json(purchaseList);
} catch (error) {
console.error('Error processing purchases:', error);
return NextResponse.json(
{ error: 'Failed to process purchases' },
{ status: 500 }
);
}
}

44
app/globals.css Normal file
View File

@@ -0,0 +1,44 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html,
body {
margin: 0;
padding: 0;
overflow-x: hidden;
overscroll-behavior: none;
width: 100%;
position: relative;
}
#root,
#__next {
overflow-x: hidden;
width: 100%;
}
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
}

20
app/layout.tsx Normal file
View File

@@ -0,0 +1,20 @@
import type { Metadata } from 'next';
import './globals.css';
export const metadata: Metadata = {
title: 'Synthetic Consumers Data Generator',
description:
'Generate realistic synthetic consumers and their weekly purchase behaviors using AI'
};
export default function RootLayout({
children
}: {
children: React.ReactNode;
}) {
return (
<html lang='en'>
<body>{children}</body>
</html>
);
}

20
app/page.tsx Normal file
View File

@@ -0,0 +1,20 @@
'use client';
import { Footer } from '@components/Footer';
import { Header } from '@components/Header';
import { Content } from '@components/Content';
import { ToastProvider } from '../context/toast/ToastProvider';
export default function Home() {
return (
<ToastProvider>
<div className='min-h-screen flex flex-col'>
<Header />
<main className='flex-1 pt-[100px] pb-[88px]'>
<Content />
</main>
<Footer />
</div>
</ToastProvider>
);
}