mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-06-01 01:03:36 +00:00
Initial commit
This commit is contained in:
28
apps/webapp/src/app/auth/confirm/route.ts
Normal file
28
apps/webapp/src/app/auth/confirm/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { type EmailOtpType } from '@supabase/supabase-js'
|
||||
import { type NextRequest } from 'next/server'
|
||||
|
||||
import { createClient } from '@/utils/supabase/server'
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const token_hash = searchParams.get('token_hash')
|
||||
const type = searchParams.get('type') as EmailOtpType | null
|
||||
const next = searchParams.get('next') ?? '/'
|
||||
|
||||
if (token_hash && type) {
|
||||
const supabase = await createClient()
|
||||
|
||||
const { error } = await supabase.auth.verifyOtp({
|
||||
type,
|
||||
token_hash,
|
||||
})
|
||||
if (!error) {
|
||||
// redirect user to specified redirect URL or root of app
|
||||
redirect(next)
|
||||
}
|
||||
}
|
||||
|
||||
// redirect the user to an error page with some instructions
|
||||
redirect('/error')
|
||||
}
|
||||
10
apps/webapp/src/app/blog/page.tsx
Normal file
10
apps/webapp/src/app/blog/page.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function BlogPage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-6 py-16">
|
||||
<h1 className="text-3xl font-semibold tracking-tight">Blog</h1>
|
||||
<p className="mt-4 text-sm text-neutral-600">
|
||||
Publish product updates, engineering notes, and launch posts here.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
12
apps/webapp/src/app/dashboard/actions.ts
Normal file
12
apps/webapp/src/app/dashboard/actions.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { createClient } from '@/utils/supabase/server'
|
||||
|
||||
export async function logout() {
|
||||
const supabase = await createClient()
|
||||
await supabase.auth.signOut()
|
||||
revalidatePath('/', 'layout')
|
||||
redirect('/login')
|
||||
}
|
||||
14
apps/webapp/src/app/dashboard/layout.tsx
Normal file
14
apps/webapp/src/app/dashboard/layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
export default function DashboardLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<nav>
|
||||
<h1>Dashboard</h1>
|
||||
</nav>
|
||||
<main>{children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
apps/webapp/src/app/dashboard/page.tsx
Normal file
21
apps/webapp/src/app/dashboard/page.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
import { createClient } from '@/utils/supabase/server'
|
||||
import { logout } from './actions'
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const supabase = await createClient()
|
||||
|
||||
const { data, error } = await supabase.auth.getUser()
|
||||
if (error || !data?.user) {
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Welcome, {data.user.email}</p>
|
||||
<form>
|
||||
<button formAction={logout}>Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
20
apps/webapp/src/app/error.tsx
Normal file
20
apps/webapp/src/app/error.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
'use client';
|
||||
|
||||
export default function Error({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
{/* TODO: Style this error page when implementing in your project */}
|
||||
<h2>Something went wrong!</h2>
|
||||
<p>{error.message || 'An unexpected error occurred'}</p>
|
||||
<button onClick={() => reset()}>
|
||||
Try again
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
5
apps/webapp/src/app/error/page.tsx
Normal file
5
apps/webapp/src/app/error/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
'use client'
|
||||
|
||||
export default function ErrorPage() {
|
||||
return <p>Sorry, something went wrong</p>
|
||||
}
|
||||
BIN
apps/webapp/src/app/favicon.ico
Normal file
BIN
apps/webapp/src/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
26
apps/webapp/src/app/globals.css
Normal file
26
apps/webapp/src/app/globals.css
Normal file
@@ -0,0 +1,26 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
8
apps/webapp/src/app/instruments/page.tsx
Normal file
8
apps/webapp/src/app/instruments/page.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
|
||||
export default async function Instruments() {
|
||||
const supabase = await createClient();
|
||||
const { data: instruments } = await supabase.from("instruments").select();
|
||||
|
||||
return <pre>{JSON.stringify(instruments, null, 2)}</pre>
|
||||
}
|
||||
29
apps/webapp/src/app/layout.tsx
Normal file
29
apps/webapp/src/app/layout.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import Header from "@/components/Header";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
const fontVariables = "font-sans";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Ultiplate - Ultimate Boilerplate",
|
||||
description: "AI-native template for any project with deployment ready setup",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${fontVariables} antialiased`}>
|
||||
<Header />
|
||||
<main className="min-h-screen">
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
46
apps/webapp/src/app/login/actions.ts
Normal file
46
apps/webapp/src/app/login/actions.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
import { createClient } from '@/utils/supabase/server'
|
||||
|
||||
export async function login(formData: FormData) {
|
||||
const supabase = await createClient()
|
||||
|
||||
// type-casting here for convenience
|
||||
// in practice, you should validate your inputs
|
||||
const data = {
|
||||
email: formData.get('email') as string,
|
||||
password: formData.get('password') as string,
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.signInWithPassword(data)
|
||||
|
||||
if (error) {
|
||||
redirect('/error')
|
||||
}
|
||||
|
||||
revalidatePath('/', 'layout')
|
||||
redirect('/')
|
||||
}
|
||||
|
||||
export async function signup(formData: FormData) {
|
||||
const supabase = await createClient()
|
||||
|
||||
// type-casting here for convenience
|
||||
// in practice, you should validate your inputs
|
||||
const data = {
|
||||
email: formData.get('email') as string,
|
||||
password: formData.get('password') as string,
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.signUp(data)
|
||||
|
||||
if (error) {
|
||||
redirect('/error')
|
||||
}
|
||||
|
||||
revalidatePath('/', 'layout')
|
||||
redirect('/')
|
||||
}
|
||||
14
apps/webapp/src/app/login/page.tsx
Normal file
14
apps/webapp/src/app/login/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { login, signup } from './actions'
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<form>
|
||||
<label htmlFor="email">Email:</label>
|
||||
<input id="email" name="email" type="email" required />
|
||||
<label htmlFor="password">Password:</label>
|
||||
<input id="password" name="password" type="password" required />
|
||||
<button formAction={login}>Log in</button>
|
||||
<button formAction={signup}>Sign up</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
12
apps/webapp/src/app/not-found.tsx
Normal file
12
apps/webapp/src/app/not-found.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div>
|
||||
{/* TODO: Style this 404 page when implementing in your project */}
|
||||
<h2>Not Found</h2>
|
||||
<p>Could not find requested resource</p>
|
||||
<Link href="/">Return Home</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
apps/webapp/src/app/page.tsx
Normal file
17
apps/webapp/src/app/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Hero from "@/components/Hero";
|
||||
import FeaturesGrid from "@/components/FeaturesGrid";
|
||||
import Testimonials1 from "@/components/Testimonials1";
|
||||
import Pricing from "@/components/Pricing";
|
||||
//import FAQ from "@/components/FAQ";
|
||||
//import CTA from "@/components/CTA";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div>
|
||||
<Hero />
|
||||
<FeaturesGrid />
|
||||
<Testimonials1 />
|
||||
<Pricing />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
10
apps/webapp/src/app/privacy-policy/page.tsx
Normal file
10
apps/webapp/src/app/privacy-policy/page.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function PrivacyPolicyPage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-6 py-16">
|
||||
<h1 className="text-3xl font-semibold tracking-tight">Privacy Policy</h1>
|
||||
<p className="mt-4 text-sm text-neutral-600">
|
||||
Describe what data you collect, how it is used, and how users can request deletion.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
10
apps/webapp/src/app/tos/page.tsx
Normal file
10
apps/webapp/src/app/tos/page.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function TermsOfServicePage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-6 py-16">
|
||||
<h1 className="text-3xl font-semibold tracking-tight">Terms of Service</h1>
|
||||
<p className="mt-4 text-sm text-neutral-600">
|
||||
Add your product terms, responsibilities, and legal limitations in this page.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user