mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 10:33:01 +00:00
replaced login page with modal
This commit is contained in:
@@ -19,15 +19,18 @@ const DEMO_USERS = [
|
||||
{ name: "User 2", username: "u2", password: "a" },
|
||||
];
|
||||
|
||||
export default function LogInForm() {
|
||||
export default function LogInForm({
|
||||
showWarning,
|
||||
setShowWarning,
|
||||
}: {
|
||||
showWarning: boolean;
|
||||
setShowWarning: (value: boolean) => void;
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { setUser } = useSession();
|
||||
|
||||
const [loginDetailsOpen, setLoginDetailsOpen] = useState(false);
|
||||
const [showWarning, setShowWarning] = useState(() => {
|
||||
return localStorage.getItem("hide-under-construction") !== "true";
|
||||
});
|
||||
|
||||
const [mode, setMode] = useState<"login" | "register">("login");
|
||||
|
||||
@@ -143,7 +146,7 @@ export default function LogInForm() {
|
||||
<>
|
||||
{/* under construction warning */}
|
||||
{showWarning && (
|
||||
<div className="relative flex flex-col border p-4 items-center border-border/50 bg-border/10 gap-2 max-w-lg">
|
||||
<div className="relative flex flex-col items-center gap-2 max-w-lg">
|
||||
<IconButton
|
||||
size="md"
|
||||
className="absolute top-2 right-2"
|
||||
@@ -168,7 +171,7 @@ export default function LogInForm() {
|
||||
<DialogTrigger className="text-primary hover:text-personality cursor-pointer mt-2">
|
||||
Login Details
|
||||
</DialogTrigger>
|
||||
<DialogContent className="w-xs" showCloseButton={false}>
|
||||
<DialogContent showCloseButton={false}>
|
||||
<DialogTitle className="sr-only">Demo Login Credentials</DialogTitle>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{DEMO_USERS.map((user) => (
|
||||
@@ -208,7 +211,7 @@ export default function LogInForm() {
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex flex-col gap-2 items-center border p-6 pb-4",
|
||||
"relative flex flex-col gap-2 items-center p-4 pb-2",
|
||||
error !== "" && "border-destructive",
|
||||
)}
|
||||
>
|
||||
|
||||
55
packages/frontend/src/components/login-modal.tsx
Normal file
55
packages/frontend/src/components/login-modal.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import LogInForm from "@/components/login-form";
|
||||
import { useSession } from "@/components/session-provider";
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface LoginModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onSuccess?: () => void;
|
||||
dismissible?: boolean;
|
||||
}
|
||||
|
||||
export function LoginModal({ open, onOpenChange, onSuccess, dismissible = true }: LoginModalProps) {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { user, isLoading } = useSession();
|
||||
const [hasRedirected, setHasRedirected] = useState(false);
|
||||
const [showWarning, setShowWarning] = useState(() => {
|
||||
return localStorage.getItem("hide-under-construction") !== "true";
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (open && !isLoading && user && !hasRedirected) {
|
||||
setHasRedirected(true);
|
||||
const next = searchParams.get("next") || "/issues";
|
||||
navigate(next, { replace: true });
|
||||
onSuccess?.();
|
||||
onOpenChange(false);
|
||||
}
|
||||
}, [open, user, isLoading, navigate, searchParams, onSuccess, onOpenChange, hasRedirected]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setHasRedirected(false);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
const handleOpenChange = (newOpen: boolean) => {
|
||||
if (!dismissible && !newOpen) {
|
||||
return;
|
||||
}
|
||||
onOpenChange(newOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent showCloseButton={false} className={cn("p-0 w-xs py-8", showWarning && "w-md pt-4")}>
|
||||
<DialogTitle className="sr-only">Log In or Register</DialogTitle>
|
||||
<LogInForm showWarning={showWarning} setShowWarning={setShowWarning} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { UserRecord } from "@sprint/shared";
|
||||
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import { Navigate, useLocation } from "react-router-dom";
|
||||
|
||||
import Loading from "@/components/loading";
|
||||
import { LoginModal } from "@/components/login-modal";
|
||||
import { clearAuth, getServerURL, setCsrfToken } from "@/lib/utils";
|
||||
|
||||
interface SessionContextValue {
|
||||
@@ -74,15 +75,22 @@ export function SessionProvider({ children }: { children: React.ReactNode }) {
|
||||
|
||||
export function RequireAuth({ children }: { children: React.ReactNode }) {
|
||||
const { user, isLoading } = useSession();
|
||||
const location = useLocation();
|
||||
const [loginModalOpen, setLoginModalOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && !user) {
|
||||
setLoginModalOpen(true);
|
||||
} else if (user) {
|
||||
setLoginModalOpen(false);
|
||||
}
|
||||
}, [user, isLoading]);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading message={"Checking authentication"} />;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
const next = encodeURIComponent(location.pathname + location.search);
|
||||
return <Navigate to={`/login?next=${next}`} replace />;
|
||||
return <LoginModal open={loginModalOpen} onOpenChange={setLoginModalOpen} dismissible={false} />;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
|
||||
Reference in New Issue
Block a user