Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/routes/ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ router.post("/chat", authMiddleware, async (req, res) => {
data: {
id: conversationId,
userId,
title: data.message.slice(0, 20) + "...",
title: data.message.slice(0, 35) + "...",
type: "CONVERSATION",
externalId: conversationId
}
Expand Down
431 changes: 271 additions & 160 deletions frontend/app/(app)/apps/[id]/page.tsx

Large diffs are not rendered by default.

25 changes: 22 additions & 3 deletions frontend/app/(app)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { SidebarToggle } from "@/app/_components/sidebar-toggle";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
"use client";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar";
import { Separator } from "@/components/ui/separator";
import { SelectTheme } from "@/components/ui/theme-toggler";
import { UIStructure } from "@/components/ui/ui-structure";
import { ThemeProvider } from "@/components/theme-provider";
import { UpgradeCTA } from "@/components/ui/upgrade-cta";
import { useUser } from "@/hooks/useUser";

import Link from "next/link";

export default function ChatLayout({
children,
}: {
children: React.ReactNode;
}) {
const { user, isLoading: isUserLoading } = useUser();

return (
<>
<SidebarProvider>
Expand All @@ -23,9 +33,18 @@ export default function ChatLayout({
<SidebarInset className="min-!h-svh p-2">
<div className="bg-muted/60 relative h-[calc(100vh-16px)] min-h-[calc(100vh-16px)] w-full rounded-xl p-4">
<div className="absolute top-0 left-0 z-[50] flex h-12 w-full items-center justify-between px-3">
<SidebarToggle />
<SidebarTrigger className="shrink-0" />
{/* <SidebarToggle /> */}
<div className="flex items-center gap-2">
<UpgradeCTA variant="topbar" />
{!isUserLoading && !user && (
<Link
href="/auth"
className="flex items-center w-full text-white dark:text-neutral-900 text-xs h-8 bg-neutral-800 dark:bg-zinc-100 font-bold px-4 rounded-2xl inset-shadow-xs inset-shadow-white/20 border border-black/4 outline-0"
>
Login
</Link>
)}
<SelectTheme />
</div>
</div>
Expand Down
133 changes: 69 additions & 64 deletions frontend/app/_components/Email.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"use client";
import { toast } from "sonner";
import { ArrowLeft } from "lucide-react";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { Input } from "@/components/ui/input";
import { BACKEND_URL } from "@/lib/utils";
import { useRouter } from "next/navigation";
import { useState } from "react";
import Link from "next/link";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";

const isEmailValid = (email: string) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
Expand All @@ -21,80 +24,82 @@ export function Email({
setStep: (step: string) => void;
email: string;
}) {
const router = useRouter();
const [sendingRequest, setSendingRequest] = useState(false);

const handleSendOTP = async () => {
const handleAuth = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setSendingRequest(true);

try {
const response = await fetch(`${BACKEND_URL}/auth/initiate_signin`, {
method: "POST",
body: JSON.stringify({ email }),
headers: {
"Content-Type": "application/json",
},
});

if (response.status === 200) {
setStep("otp");
toast.success("OTP sent to email");
} else {
fetch(`${BACKEND_URL}/auth/initiate_signin`, {
method: "POST",
body: JSON.stringify({ email }),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.status === 200) {
setStep("otp");
toast.success("OTP sent to email");
} else {
toast.error("Failed to send OTP, please retry after a few minutes");
}
})
.catch((err) => {
console.error(err);
toast.error("Failed to send OTP, please retry after a few minutes");
}
} catch (err) {
console.error(err);
toast.error("Failed to send OTP, please retry after a few minutes");
} finally {
setSendingRequest(false);
}
})
.finally(() => {
setSendingRequest(false);
});
};

return (
<div className="mx-auto max-h-screen max-w-6xl">
<div className="absolute top-4 left-4">
{/* <Button asChild variant="ghost" className="font-semibold" onClick={() => router.push("/")}>
<Link className="flex items-center gap-2" href="/">
<ArrowLeft className="size-4" />
Back to chat
</Link>
</Button> */}
</div>
<div className="flex h-full flex-col items-center justify-center gap-8 max-w-xl ">
<h1 className="text-3xl lg:text-4xl font-bold tracking-tighter text-center">
Welcome to <span className="text-primary">1ai</span>
<div className="mx-auto w-full max-h-screen max-w-sm px-2 sm:px-0">
<div className="flex h-full flex-col items-center justify-center gap-8">
<h1 className="text-3xl font-serif text-foreground">
Welcome to 1<span className="text-orange-400">ai</span>
</h1>
<div className="w-full flex flex-col gap-2">
<Input
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
onKeyDown={(e) => {
if (e.key === "Enter" && isEmailValid(email) && !sendingRequest) {
handleSendOTP();
}
}}
/>
<form onSubmit={handleAuth} className="w-full flex flex-col gap-3">
<div className="border border-zinc-400/15 focus-within:border-transparent focus-within:ring-1 rounded-xl focus-within:ring-orange-400/80 dark:focus-within:ring-orange-400/60">
<Input
className="border-none dark:bg-transparent focus:border-none focus-visible:ring-0 outline-none focus:ring-0"
spellCheck={false}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
</div>
<Button
type="submit"
disabled={!isEmailValid(email) || sendingRequest}
variant="accent"
onClick={() => {
if (isEmailValid(email) && !sendingRequest) {
handleSendOTP();
}
}}
className="w-full h-12"
className="w-full text-sm text-white bg-[#fa7319] hover:bg-[#fa7319]/90 h-10 px-3.5 rounded-xl inset-shadow-sm inset-shadow-white/60 font-medium border border-black/4 outline-0"
>
Continue with Email
</Button>
</div>
<div className="text-muted-foreground text-sm">
By continuing, you agree to our{" "}
<Link href="/terms" className="text-muted-foreground font-medium">
Terms
</Link>{" "}
and{" "}
<Link href="/privacy" className="text-muted-foreground font-medium">
Privacy Policy
</Link>
</form>
<div className="mt-2">
<Tooltip>
<TooltipTrigger>
<div className="group text-muted-foreground text-sm font-serif">
<Link
href="/terms"
className="text-muted-foreground group-hover:text-orange-400 hover:underline hover:underline-offset-3"
>
Terms
</Link>{" "}
<span className="group-hover:text-orange-400">and </span>
<Link
href="/privacy"
className="text-muted-foreground group-hover:text-orange-400 hover:underline hover:underline-offset-3"
>
Privacy Policy
</Link>
</div>
</TooltipTrigger>
<TooltipContent sideOffset={1}>
<p>By continuing, you agree</p>
</TooltipContent>
</Tooltip>
</div>
</div>
</div>
Expand Down
Loading