fix: login module fixed to handle new flag logic

This commit is contained in:
talatops 2026-03-04 22:04:22 +05:00
parent 387cfb0aa2
commit 54d38755d8
2 changed files with 111 additions and 76 deletions

View File

@ -1,22 +1,30 @@
## JUNO
<p align="center"> <p align="center">
<img src="./public/icon.png" alt="JUNO logo" width="420" /> <img src="./public/icon.png" alt="JUNO logo" width="260" />
</p> </p>
**Tech stack** <h1 align="center">JUNO</h1>
![Next.js](https://img.shields.io/badge/Next.js-000000?logo=nextdotjs&logoColor=white) <p align="center">
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white) 🚀 Modern commerce & AI‑powered support infrastructure for Shopify‑based dropshipping businesses.
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white) </p>
![AWS Bedrock](https://img.shields.io/badge/AWS%20Bedrock-232F3E?logo=amazonaws&logoColor=white)
![Gmail API](https://img.shields.io/badge/Gmail%20API-EA4335?logo=gmail&logoColor=white)
![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white)
![NextAuth](https://img.shields.io/badge/NextAuth-000000?logo=nextdotjs&logoColor=white)
![Shopify API](https://img.shields.io/badge/Shopify%20API-7AB55C?logo=shopify&logoColor=white)
![AES Encryption](https://img.shields.io/badge/AES%20Encryption-4B0082)
Modern commerce and support infrastructure for Shopify‑based dropshipping businesses. 🚀 <p align="center">
<strong>Tech stack</strong>
</p>
<p align="center">
<img src="https://img.shields.io/badge/Next.js-000000?logo=nextdotjs&logoColor=white" alt="Next.js" />
<img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white" alt="TypeScript" />
<img src="https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white" alt="PostgreSQL" />
<img src="https://img.shields.io/badge/AWS%20Bedrock-232F3E?logo=amazonaws&logoColor=white" alt="AWS Bedrock" />
<img src="https://img.shields.io/badge/Gmail%20API-EA4335?logo=gmail&logoColor=white" alt="Gmail API" />
<img src="https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white" alt="Docker" />
<img src="https://img.shields.io/badge/NextAuth-000000?logo=nextdotjs&logoColor=white" alt="NextAuth" />
<img src="https://img.shields.io/badge/Shopify%20API-7AB55C?logo=shopify&logoColor=white" alt="Shopify API" />
<img src="https://img.shields.io/badge/AES%20Encryption-4B0082" alt="AES Encryption" />
</p>
---
JUNO is a full‑stack Next.js application that powers: JUNO is a full‑stack Next.js application that powers:
@ -25,11 +33,11 @@ JUNO is a full‑stack Next.js application that powers:
- An **Admin view** for operations - An **Admin view** for operations
- An AI‑powered helpdesk and knowledge engine called **JUNOCHAT / Juno Engine** - An AI‑powered helpdesk and knowledge engine called **JUNOCHAT / Juno Engine**
Everything runs inside a single Next.js App Router project (frontend + backend + background jobs). Everything runs inside a single Next.js App Router project (frontend + backend + background jobs). 💻
--- ---
## Table of Contents ## 📚 Table of Contents
1. [High‑Level Overview](#high-level-overview) 1. [High‑Level Overview](#high-level-overview)
2. [Core Features](#core-features) 2. [Core Features](#core-features)
@ -49,7 +57,7 @@ Everything runs inside a single Next.js App Router project (frontend + backend +
--- ---
## High‑Level Overview ## 🧭 High‑Level Overview
JUNO centralizes communication and operations between **vendors** (Shopify stores) and **suppliers**: JUNO centralizes communication and operations between **vendors** (Shopify stores) and **suppliers**:
@ -71,9 +79,9 @@ JUNO centralizes communication and operations between **vendors** (Shopify store
--- ---
## Core Features ## ✨ Core Features
### Vendor Portal ### 🛍️ Vendor Portal
- **Shopify connections** - **Shopify connections**
- Connect one or more Shopify stores to JUNO. - Connect one or more Shopify stores to JUNO.
@ -104,7 +112,7 @@ JUNO centralizes communication and operations between **vendors** (Shopify store
- A supplier provides a new product. - A supplier provides a new product.
- A supplier updates the price or quantity of an offered/synced product. - A supplier updates the price or quantity of an offered/synced product.
### Supplier Portal ### 🤝 Supplier Portal
- **Vendor Connections** - **Vendor Connections**
- Accept invitations using secure tokens. - Accept invitations using secure tokens.
@ -142,7 +150,7 @@ JUNO centralizes communication and operations between **vendors** (Shopify store
- Synced products from vendors are **editable but not deletable**. - Synced products from vendors are **editable but not deletable**.
- UI labels clarify when a product is “Synced” and where it came from. - UI labels clarify when a product is “Synced” and where it came from.
### Admin / Ops ### 🛠️ Admin / Ops
- Admin page with an overview of: - Admin page with an overview of:
- Stores - Stores
@ -155,7 +163,7 @@ JUNO centralizes communication and operations between **vendors** (Shopify store
- Email logs and templates. - Email logs and templates.
- MFA setup, notifications, and account hygiene flows. - MFA setup, notifications, and account hygiene flows.
### JUNOCHAT (AI Helpdesk) ### 🤖 JUNOCHAT (AI Helpdesk)
JUNOCHAT (a.k.a. Juno Engine chat) is the AI layer that: JUNOCHAT (a.k.a. Juno Engine chat) is the AI layer that:

View File

@ -1,14 +1,14 @@
"use client" "use client"
import { signIn } from "next-auth/react" import { signIn } from "next-auth/react"
import { useEffect, useState } from "react" import { Suspense, useEffect, useState } from "react"
import { useRouter, useSearchParams } from "next/navigation" import { useRouter, useSearchParams } from "next/navigation"
import { motion } from "framer-motion" import { motion } from "framer-motion"
import { Mail, Lock, Loader2, Shield, ShoppingBag, Truck } from "lucide-react" import { Mail, Lock, Loader2, Shield, ShoppingBag, Truck } from "lucide-react"
import Link from "next/link" import Link from "next/link"
import Image from "next/image" import Image from "next/image"
export default function LoginPage() { function LoginFormContent() {
const router = useRouter() const router = useRouter()
const searchParams = useSearchParams() const searchParams = useSearchParams()
const initialRoleFromQuery = const initialRoleFromQuery =
@ -143,15 +143,8 @@ export default function LoginPage() {
} }
return ( return (
<div className="min-h-screen flex items-center justify-center p-4 md:p-6 relative overflow-hidden auth-glass-dark"> <div className="bg-white/5 backdrop-blur-xl rounded-2xl md:rounded-3xl p-6 md:p-8 border border-white/10">
<motion.div <div className="text-center mb-10">
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="w-full max-w-md relative z-10"
>
<div className="bg-white/5 backdrop-blur-xl rounded-2xl md:rounded-3xl p-6 md:p-8 border border-white/10">
<div className="text-center mb-10">
<div className="inline-flex items-center justify-center gap-3 mb-4"> <div className="inline-flex items-center justify-center gap-3 mb-4">
<div className="w-14 h-14 rounded-2xl bg-indigo-500/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20"> <div className="w-14 h-14 rounded-2xl bg-indigo-500/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20">
<Image <Image
@ -170,9 +163,9 @@ export default function LoginPage() {
<p className="text-slate-400 text-sm"> <p className="text-slate-400 text-sm">
Access your dropshipping empire. Access your dropshipping empire.
</p> </p>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 md:gap-4 mb-6"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 md:gap-4 mb-6">
<button <button
type="button" type="button"
onClick={() => setRole("VENDOR")} onClick={() => setRole("VENDOR")}
@ -220,9 +213,9 @@ export default function LoginPage() {
Log in to your supplier portal Log in to your supplier portal
</div> </div>
</button> </button>
</div> </div>
<form onSubmit={handleCredentialsLogin} className="space-y-4"> <form onSubmit={handleCredentialsLogin} className="space-y-4">
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<label className="block text-xs font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1"> <label className="block text-xs font-bold text-slate-400 uppercase tracking-widest mb-1.5 ml-1">
@ -309,11 +302,11 @@ export default function LoginPage() {
</p> </p>
)} )}
<button <button
type="submit" type="submit"
disabled={loading} disabled={loading}
className="w-full h-12 bg-indigo-500 hover:bg-indigo-600 text-white font-bold rounded-xl transition-all duration-200 flex items-center justify-center gap-2 group cursor-pointer disabled:opacity-70 disabled:cursor-not-allowed border border-indigo-400/20" className="w-full h-12 bg-indigo-500 hover:bg-indigo-600 text-white font-bold rounded-xl transition-all duration-200 flex items-center justify-center gap-2 group cursor-pointer disabled:opacity-70 disabled:cursor-not-allowed border border-indigo-400/20"
> >
{loading ? ( {loading ? (
<Loader2 className="w-5 h-5 animate-spin" /> <Loader2 className="w-5 h-5 animate-spin" />
) : ( ) : (
@ -322,44 +315,78 @@ export default function LoginPage() {
<span className="group-hover:translate-x-1 transition-transform duration-200">→</span> <span className="group-hover:translate-x-1 transition-transform duration-200">→</span>
</> </>
)} )}
</button> </button>
</form> </form>
<div className="relative my-8"> <div className="relative my-8">
<div className="absolute inset-0 flex items-center"> <div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-white/10"></div> <div className="w-full border-t border-white/10"></div>
</div>
<div className="relative flex justify-center text-[10px] uppercase font-bold tracking-widest">
<span className="bg-transparent px-4 text-slate-500">Or continue with</span>
</div>
</div>
<button
onClick={handleGoogleSignIn}
type="button"
className="w-full h-12 flex items-center justify-center gap-3 bg-white/10 border border-white/10 text-white font-bold rounded-xl hover:bg-white/15 backdrop-blur-sm transition-all duration-200 cursor-pointer"
>
<svg className="w-5 h-5" viewBox="0 0 24 24">
<path fill="#EA4335" d="M5.2662 9.76453C6.19903 6.93863 8.85469 4.90909 12 4.90909C13.6909 4.90909 15.2182 5.50909 16.4182 6.49091L19.9091 3C17.7818 1.14545 15.0545 0 12 0C7.27273 0 3.19091 2.69091 1.24545 6.65455L5.2662 9.76453Z" />
<path fill="#4285F4" d="M23.4909 12.2727C23.4909 11.4909 23.4182 10.7455 23.2909 10H12V14.5091H18.4364C18.1455 16.0364 17.2909 17.3091 16 18.2182L19.9091 21.2727C22.1818 19.1818 23.4909 16.0364 23.4909 12.2727Z" />
<path fill="#FBBC05" d="M5.26649 14.2355C5.02103 13.4909 4.88182 12.7091 4.88182 11.8909C4.88182 11.0727 5.02103 10.2909 5.26649 9.54545L1.24545 6.43636C0.454545 8.05455 0 9.87273 0 11.8909C0 13.9091 0.454545 15.7273 1.24545 17.3455L5.26649 14.2355Z" />
<path fill="#34A853" d="M12 24C15.0545 24 17.7818 22.9091 19.9091 21.0545L16 18C14.8909 18.7273 13.5273 19.1818 12 19.1818C8.85469 19.1818 6.19903 17.1522 5.2662 14.3263L1.24545 17.4364C3.19091 21.3636 7.27273 24 12 24Z" />
</svg>
Google
</button>
<p className="text-center mt-8 text-sm text-slate-400 font-medium">
Don&apos;t have an account?{" "}
<Link href="/signup" className="text-indigo-400 hover:underline decoration-indigo-400/50 underline-offset-4 font-bold transition-all">
Create an account
</Link>
</p>
</div> </div>
<div className="relative flex justify-center text-[10px] uppercase font-bold tracking-widest">
<span className="bg-transparent px-4 text-slate-500">Or continue with</span>
</div>
</div>
<button
onClick={handleGoogleSignIn}
type="button"
className="w-full h-12 flex items-center justify-center gap-3 bg-white/10 border border-white/10 text-white font-bold rounded-xl hover:bg-white/15 backdrop-blur-sm transition-all duration-200 cursor-pointer"
>
<svg className="w-5 h-5" viewBox="0 0 24 24">
<path
fill="#EA4335"
d="M5.2662 9.76453C6.19903 6.93863 8.85469 4.90909 12 4.90909C13.6909 4.90909 15.2182 5.50909 16.4182 6.49091L19.9091 3C17.7818 1.14545 15.0545 0 12 0C7.27273 0 3.19091 2.69091 1.24545 6.65455L5.2662 9.76453Z"
/>
<path
fill="#4285F4"
d="M23.4909 12.2727C23.4909 11.4909 23.4182 10.7455 23.2909 10H12V14.5091H18.4364C18.1455 16.0364 17.2909 17.3091 16 18.2182L19.9091 21.2727C22.1818 19.1818 23.4909 16.0364 23.4909 12.2727Z"
/>
<path
fill="#FBBC05"
d="M5.26649 14.2355C5.02103 13.4909 4.88182 12.7091 4.88182 11.8909C4.88182 11.0727 5.02103 10.2909 5.26649 9.54545L1.24545 6.43636C0.454545 8.05455 0 9.87273 0 11.8909C0 13.9091 0.454545 15.7273 1.24545 17.3455L5.26649 14.2355Z"
/>
<path
fill="#34A853"
d="M12 24C15.0545 24 17.7818 22.9091 19.9091 21.0545L16 18C14.8909 18.7273 13.5273 19.1818 12 19.1818C8.85469 19.1818 6.19903 17.1522 5.2662 14.3263L1.24545 17.4364C3.19091 21.3636 7.27273 24 12 24Z"
/>
</svg>
Google
</button>
<p className="text-center mt-8 text-sm text-slate-400 font-medium">
Don&apos;t have an account?{" "}
<Link
href="/signup"
className="text-indigo-400 hover:underline decoration-indigo-400/50 underline-offset-4 font-bold transition-all"
>
Create an account
</Link>
</p>
</div>
)
}
export default function LoginPage() {
return (
<div className="min-h-screen flex items-center justify-center p-4 md:p-6 relative overflow-hidden auth-glass-dark">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="w-full max-w-md relative z-10"
>
<Suspense
fallback={
<div className="bg-white/5 backdrop-blur-xl rounded-2xl md:rounded-3xl p-6 md:p-8 border border-white/10 flex items-center justify-center min-h-[320px]">
<Loader2 className="w-8 h-8 animate-spin text-indigo-500" />
</div>
}
>
<LoginFormContent />
</Suspense>
<div className="mt-8 space-y-2 text-center text-slate-500 text-[10px] uppercase tracking-widest font-bold"> <div className="mt-8 space-y-2 text-center text-slate-500 text-[10px] uppercase tracking-widest font-bold">
<div> <div>JUNO Systems &copy; 2026</div>
JUNO Systems &copy; 2026
</div>
<div className="flex items-center justify-center gap-4 text-[9px] font-semibold normal-case text-slate-400"> <div className="flex items-center justify-center gap-4 text-[9px] font-semibold normal-case text-slate-400">
<Link <Link
href="/privacy-policy" href="/privacy-policy"