minimal dashboard

This commit is contained in:
2025-02-15 13:30:38 +01:00
parent b4b2abde0f
commit c7f4290b98
21 changed files with 3052 additions and 79 deletions
+11 -8
View File
@@ -10,9 +10,13 @@ import { generateUrlSafeString } from '@/utils';
// Email doesn't exist
// Password is between 6-20 characters
export async function POST(req: NextRequest) {
const { email, password } = await req.json();
const { email, password, name } = await req.json();
if (typeof email !== 'string' || typeof password !== 'string')
if (
typeof email !== 'string' ||
typeof password !== 'string' ||
typeof name !== 'string'
)
return NextResponse.json(
{
message:
@@ -29,18 +33,17 @@ export async function POST(req: NextRequest) {
{ status: 409 }
);
await database.users.insertOne({ email, password });
await database.users.insertOne({ email, password, name });
const response = NextResponse.json(
const sessionId = (await database.sessions.insertOne({ email })).insertedId;
return NextResponse.json(
{
message: 'ok',
sessionId,
},
{ status: 200 }
);
response.cookies.set('session_id', generateUrlSafeString(16));
return;
}
// Account login
+46
View File
@@ -0,0 +1,46 @@
import Engagement from '@/components/engagement';
import { Calendar } from '@/components/ui/calendar';
import {
SidebarProvider,
Sidebar,
SidebarContent,
} from '@/components/ui/sidebar';
import { DayPicker } from 'react-day-picker';
export default function Dashboard() {
return (
<div className="flex w-full">
<div>
<SidebarProvider>
<Sidebar className="w-64 h-full">
<SidebarContent className="p-6">Hello</SidebarContent>
</Sidebar>
</SidebarProvider>
</div>
<div className="flex flex-1 flex-col p-6 px-10 h-max">
<div className="w-full">
<h1 className="text-3xl font-bold">Dashboard</h1>
</div>
<div className="w-full mt-5 flex flex-col xl:flex-row gap-5 items-stretch">
<Engagement />
<div className="w-full pb-7 border rounded-2xl">
<Calendar
className="h-full w-full flex"
classNames={{
months: 'flex w-full flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0 flex-1',
month: 'space-y-4 w-full flex flex-col',
table: 'w-full h-full border-collapse space-y-1',
head_row: '',
row: 'w-full mt-2',
day: 'px-1 py-2 rounded-xl text-xl',
}}
/>
</div>
</div>
</div>
</div>
);
}
+61 -60
View File
@@ -3,70 +3,71 @@
@tailwind utilities;
body {
font-family: Arial, Helvetica, sans-serif;
font-family: Arial, Helvetica, sans-serif;
}
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 72.2% 50.6%;
--primary-foreground: 0 85.7% 97.3%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 72.2% 50.6%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 72.2% 50.6%;
--primary-foreground: 0 85.7% 97.3%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 72.2% 50.6%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
+45 -1
View File
@@ -1,5 +1,49 @@
'use client';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import Link from 'next/link';
export default function Login() {
return <div className="bg-[#ccc] w-1/2 h-screen ml-auto"></div>;
return (
// <div className="bg-white dark:bg-black w-[46%] h-screen ml-auto">
<div className="bg-white dark:bg-black w-full h-screen flex justify-center items-center">
<div className="text-center">
<div className="pb-5">
<h1 className="text-xl pb-2">Log in to your account</h1>
<Label className="text-sm text-muted-foreground">
Enter your credentials below to access your account
</Label>
<Input
className="w-80 mt-5 mx-auto"
type="email"
placeholder="[email protected]"
/>
<Input
className="w-80 mt-5 mx-auto"
type="password"
placeholder="Your password"
/>
<Button className="mt-5 w-80 mx-auto">Log in</Button>
</div>
<div className="w-72 mx-auto">
<Label className="mt-3 text-sm text-muted-foreground break-words">
By clicking continue, you agree to our{' '}
<Link href="/terms" className="underline">
Terms of Service
</Link>{' '}
{'and '}
<Link href="/privacy" className="underline">
Privacy Policy
</Link>
.
</Label>
</div>
</div>
</div>
// </div>
);
}
+12 -7
View File
@@ -1,9 +1,14 @@
'use client';
import { cookies } from 'next/headers';
export default function Home() {
return (
<div>
<h1 className="text-2xl">The ultimate social media manager</h1>
</div>
);
import { redirect } from 'next/navigation';
export default async function Home() {
const cookieStore = await cookies();
const sessionId = cookieStore.get('session_id');
if (sessionId) {
redirect('/dashboard');
} else {
redirect('/login');
}
return 'redirecting...';
}
+38 -2
View File
@@ -4,8 +4,16 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import Link from 'next/link';
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/navigation';
export default function SignUp() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const router = useRouter();
return (
// <div className="bg-white dark:bg-black w-[46%] h-screen ml-auto">
<div className="bg-white dark:bg-black w-full h-screen flex justify-center items-center">
@@ -18,22 +26,50 @@ export default function SignUp() {
<Input
className="w-80 mt-6 mx-auto"
placeholder="Full name"
onChange={(event) => setName(event.target.value)}
/>
<Input
className="w-80 mt-5 mx-auto"
type="email"
placeholder="[email protected]"
onChange={(event) => setEmail(event.target.value)}
/>
<Input
className="w-80 mt-5 mx-auto"
type="password"
placeholder="Enter a password"
onChange={(event) => setPassword(event.target.value)}
/>
<Button className="mt-5 w-80 mx-auto">
Sign in with Email
<Button
className="mt-5 w-80 mx-auto"
onClick={() => {
console.log('Name:', name);
console.log('Email:', email);
console.log('Password:', password);
axios
.post('/api/account/', {
name,
email,
password,
})
.then(async (response) => {
document.cookie = `session_id=${response.data.sessionId}`;
console.log(
'Account created with session',
response.data
);
router.push('/dashboard');
})
.catch((err) => {
console.error(err);
});
}}
>
Create account
</Button>
</div>
<div className="w-72 mx-auto">