Skip to content

Commit

Permalink
v2 redesign the whole pages
Browse files Browse the repository at this point in the history
  • Loading branch information
git-create-devben committed Aug 3, 2024
1 parent 108ec7c commit cfafafb
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 148 deletions.
30 changes: 16 additions & 14 deletions app/api/create-session/route.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import { NextRequest, NextResponse } from 'next/server';
import { adminAuth as auth } from '@/lib/firebaseAdmin';
import { NextRequest, NextResponse } from "next/server";
import { adminAuth as auth } from "@/lib/firebaseAdmin";

export async function POST(req: NextRequest) {
const { idToken } = await req.json();

try {
const expiresIn = 60 * 60 * 24 * 5 * 1000; // 5 days
const sessionCookie = await auth.createSessionCookie(idToken, { expiresIn });

const response = NextResponse.json({ status: 'success' });
response.cookies.set('session', sessionCookie, {
maxAge: expiresIn,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/'
const sessionCookie = await auth.createSessionCookie(idToken, {
expiresIn,
});


const response = NextResponse.json({ status: "success" });
response.cookies.set("session", sessionCookie, {
maxAge: expiresIn,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
path: "/",
});

return response;
} catch (error) {
console.error('Error creating session:', error);
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
console.error("Error creating session:", error);
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
}
}
47 changes: 27 additions & 20 deletions app/api/gemini/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@ const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || "");
export async function POST(req: NextRequest) {
try {
// Get the authorization token from the request headers
// Get the session cookie from the request
const sessionCookie = req.cookies.get('session')?.value;

if (!sessionCookie) {
return NextResponse.json({ error: "No session cookie found" }, { status: 401 });
}

// Verify the session cookie
const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie, true);

// Fetch user data from Firestore
const userDoc = await admindb.collection("users").doc(decodedClaims.uid).get();
const userData = userDoc.data();
const userName = userData?.name || "User";


// Get the session cookie from the request
const sessionCookie = req.cookies.get("session")?.value;

if (!sessionCookie) {
return NextResponse.json(
{ error: "No session cookie found" },
{ status: 401 },
);
}

// Verify the session cookie
const decodedClaims = await adminAuth.verifySessionCookie(
sessionCookie,
true,
);

// Fetch user data from Firestore
const userDoc = await admindb
.collection("users")
.doc(decodedClaims.uid)
.get();
const userData = userDoc.data();
const userName = userData?.name || "User";

// Parse the request body to get userMessage, latitude, and longitude
const { userMessage, latitude, longitude } = await req.json();
Expand Down Expand Up @@ -75,10 +82,10 @@ export async function POST(req: NextRequest) {
// Modify the prompt to include the user's name
const prompt = `You are Loca, a local AI service finder. You're talking to ${userName}.Here is some important information about you (Loca) in the form of FAQs:
${JSON.stringify(faqs)} ${
services.length > 0
? `Here are some available services: ${JSON.stringify(services)}. Provide a helpful response based on this information, highlighting the best options for ${userName}.`
: `Provide a general response about "${userMessage}" for ${userName}. If they are asking about local services, suggest how they might find them using your ${faqs} aor just let them know to turn on their location, tell them to give you access to thier location cause you will need that to get them services near them.`
}`;
services.length > 0
? `Here are some available services: ${JSON.stringify(services)}. Provide a helpful response based on this information, highlighting the best options for ${userName}.`
: `Provide a general response about "${userMessage}" for ${userName}. If they are asking about local services, suggest how they might find them using your ${faqs} aor just let them know to turn on their location, tell them to give you access to thier location cause you will need that to get them services near them.`
}`;

// Generate content stream from the AI model based on the prompt
const result = await model.generateContentStream(prompt);
Expand Down
8 changes: 4 additions & 4 deletions app/api/verify-session/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { NextRequest, NextResponse } from 'next/server';
import { adminAuth as auth } from '@/lib/firebaseAdmin';
import { NextRequest, NextResponse } from "next/server";
import { adminAuth as auth } from "@/lib/firebaseAdmin";

export async function GET(req: NextRequest) {
const sessionCookie = req.cookies.get('session')?.value || '';
const sessionCookie = req.cookies.get("session")?.value || "";

try {
const decodedClaims = await auth.verifySessionCookie(sessionCookie, true);
return NextResponse.json({ authenticated: true, user: decodedClaims });
} catch (error) {
return NextResponse.json({ authenticated: false }, { status: 401 });
}
}
}
43 changes: 22 additions & 21 deletions app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export default function Chat() {

verifySession();
}, [router]);

useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (sidebarRef.current && !sidebarRef.current.contains(event.target as Node)) {
Expand Down Expand Up @@ -87,29 +88,29 @@ export default function Chat() {

return (
<main className="flex h-screen bg-black overflow-hidden">
<FirstVisitPopup />
<div className="hidden lg:block">
<Sidebar />
</div>
<div className="flex-1 flex flex-col">
<nav className="flex justify-between p-4 sticky top-0 z-10">
<button className="lg:hidden text-white" onClick={() => setIsSidebarOpen(!isSidebarOpen)}>
<MenuIcon />
</button>
<span className="text-[#caccce] font-medium text-3xl cursor-pointer" onClick={() => window.location.href = "/"}>
Loca
</span>
<div className="flex gap-6 items-center">
<button className="lg:hidden text-[#ccc]" onClick={SignOut}>
<LogOut />
<FirstVisitPopup />
<div className="hidden lg:block">
<Sidebar />
</div>
<div className="flex-1 flex flex-col">
<nav className="flex justify-between items-center p-4 sticky top-0 z-10">
<button className="lg:hidden text-white" onClick={() => setIsSidebarOpen(!isSidebarOpen)}>
<MenuIcon />
</button>
<Image src={image} alt="user" className="rounded-full" width={50} height={50} />
<span className="text-[#caccce] font-medium text-3xl cursor-pointer items-center" onClick={() => window.location.href = "/"}>
Loca
</span>
<div className="flex gap-6 items-center">
<button className="lg:hidden text-[#ccc]" onClick={SignOut}>
<LogOut />
</button>
<Image src={image} alt="user" className="rounded-full" width={50} height={50} />
</div>
</nav>
<div className="flex-1 overflow-hidden">
<Main />
</div>
</nav>
<div className="flex-1 overflow-hidden">
<Main />
</div>
</div>
<AnimatePresence>
{isSidebarOpen && (
<motion.div
Expand All @@ -132,4 +133,4 @@ export default function Chat() {
</AnimatePresence>
</main>
);
}
}
1 change: 0 additions & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
}
}


@keyframes fadeIn {
from {
opacity: 0;
Expand Down
6 changes: 2 additions & 4 deletions components/booking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export function Booking({
loading="eager"
onError={handleMapError}
title={`Map of ${locationName || "service location"}`}
// referrerpolicy="no-referrer-when-downgrade"
// referrerpolicy="no-referrer-when-downgrade"
></iframe>
) : (
<div className="bg-gray-100 p-4 text-center">
Expand Down Expand Up @@ -196,8 +196,6 @@ export function Booking({
>
ReadMore on How we use Loca to Book you a service provider
</Link>


</div>
<DialogFooter className="sm:justify-start">
<DialogClose asChild>
Expand Down Expand Up @@ -283,7 +281,7 @@ export function Booking({
loading="eager"
onError={handleMapError}
title={`Map of ${locationName || "service location"}`}
// referrerpolicy="no-referrer-when-downgrade"
// referrerpolicy="no-referrer-when-downgrade"
></iframe>
) : (
<div className="bg-gray-100 p-4 text-center">
Expand Down
47 changes: 36 additions & 11 deletions components/bookingForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ export function BookingForm() {
message: "",
});

const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
setErrors(prev => ({ ...prev, [name]: "" }));
setFormData((prev) => ({ ...prev, [name]: value }));
setErrors((prev) => ({ ...prev, [name]: "" }));
};

const validate = () => {
Expand Down Expand Up @@ -78,11 +80,18 @@ export function BookingForm() {
<div className="bg-gray-800 rounded-lg p-6 w-full max-w-md">
<div className="flex justify-between items-center mb-4">
<h2 className="text-white text-xl font-bold">Booking Form</h2>
<button onClick={() => setIsOpen(false)} className="text-white">&times;</button>
<button onClick={() => setIsOpen(false)} className="text-white">
&times;
</button>
</div>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block text-white text-sm font-bold mb-2">Your name</label>
<label
htmlFor="name"
className="block text-white text-sm font-bold mb-2"
>
Your name
</label>
<input
type="text"
id="name"
Expand All @@ -92,10 +101,17 @@ export function BookingForm() {
className="w-full px-3 py-2 text-white bg-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-400"
placeholder="Your name"
/>
{errors.name && <p className="text-red-500 text-xs mt-1">{errors.name}</p>}
{errors.name && (
<p className="text-red-500 text-xs mt-1">{errors.name}</p>
)}
</div>
<div>
<label htmlFor="email" className="block text-white text-sm font-bold mb-2">Email</label>
<label
htmlFor="email"
className="block text-white text-sm font-bold mb-2"
>
Email
</label>
<input
type="email"
id="email"
Expand All @@ -105,10 +121,17 @@ export function BookingForm() {
className="w-full px-3 py-2 text-white bg-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-400"
placeholder="Email"
/>
{errors.email && <p className="text-red-500 text-xs mt-1">{errors.email}</p>}
{errors.email && (
<p className="text-red-500 text-xs mt-1">{errors.email}</p>
)}
</div>
<div>
<label htmlFor="message" className="block text-white text-sm font-bold mb-2">Description</label>
<label
htmlFor="message"
className="block text-white text-sm font-bold mb-2"
>
Description
</label>
<textarea
id="message"
name="message"
Expand All @@ -118,7 +141,9 @@ export function BookingForm() {
placeholder="Describe your services here"
rows={4}
/>
{errors.message && <p className="text-red-500 text-xs mt-1">{errors.message}</p>}
{errors.message && (
<p className="text-red-500 text-xs mt-1">{errors.message}</p>
)}
</div>
<button
type="submit"
Expand All @@ -132,4 +157,4 @@ export function BookingForm() {
)}
</>
);
}
}
40 changes: 10 additions & 30 deletions components/chatInbox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { SendHorizontalIcon } from "lucide-react";
import { motion } from 'framer-motion';

export const ChatInbox: React.FC<ChatInboxProps> = ({
textareaRef,
Expand All @@ -10,24 +9,14 @@ export const ChatInbox: React.FC<ChatInboxProps> = ({
locationError,
}) => {
return (
<motion.div
className="border-t border-gray-700 p-4"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<div className="border-t border-gray-700 w-full max-w-5xl p-4">
{locationError && (
<motion.div
className="mb-2"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3 }}
>
<div className="mb-2">
<p className="text-red-500 text-sm">{locationError}</p>
</motion.div>
</div>
)}
<div className="flex items-center gap-2">
<motion.textarea
<textarea
ref={textareaRef}
value={userMessage}
onChange={handleInput}
Expand All @@ -37,27 +26,18 @@ export const ChatInbox: React.FC<ChatInboxProps> = ({
disabled={isProcessing}
rows={1}
style={{ maxHeight: "6rem" }}
whileFocus={{ scale: 1.02 }}
transition={{ duration: 0.2 }}
/>
<motion.button
<button
className={`text-white p-2 rounded-full ${isProcessing ? 'opacity-50 cursor-not-allowed' : 'bg-blue-500 hover:bg-blue-600'}`}
onClick={() => !isProcessing && handleSendMessage()}
disabled={isProcessing}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
>
<SendHorizontalIcon className="w-5 h-5" />
</motion.button>
</button>
</div>
<motion.p
className="text-gray-400 text-xs text-center mt-2"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3, delay: 0.2 }}
>
<p className="text-gray-400 text-xs text-center mt-2">
<b>LOCA</b> uses your input to fetch services. Keep your input brief for more accurate results.
</motion.p>
</motion.div>
</p>
</div>
);
}
};
Loading

0 comments on commit cfafafb

Please sign in to comment.