Improve flow of joining a tablo
This commit is contained in:
parent
4f207099a3
commit
aafec28885
9 changed files with 99 additions and 27 deletions
|
|
@ -45,14 +45,7 @@ export const App = () => {
|
|||
</Layout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="join/:tablo_name"
|
||||
element={
|
||||
<Layout>
|
||||
<JoinPage />
|
||||
</Layout>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="devis"
|
||||
element={
|
||||
|
|
@ -104,6 +97,24 @@ export const App = () => {
|
|||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<ProtectedRoute
|
||||
fallback="/login"
|
||||
shouldRedirectToCurrentPage
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
path="join/:tablo_name"
|
||||
element={
|
||||
<Layout>
|
||||
<JoinPage />
|
||||
</Layout>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="login-with-oauth" element={<OAuthSigninPage />} />
|
||||
<Route path="landing" element={<LandingPage />} />
|
||||
<Route element={<PublicRoute />}>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ describe("LoginWithGoogle", () => {
|
|||
loginWithGoogle: mockLoginWithGoogle,
|
||||
});
|
||||
|
||||
render(<LoginWithGoogle />);
|
||||
render(<LoginWithGoogle redirectUrl={null} />);
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: /Continuer avec Google/i,
|
||||
|
|
@ -28,7 +28,7 @@ describe("LoginWithGoogle", () => {
|
|||
loginWithGoogle: mockLoginWithGoogle,
|
||||
});
|
||||
|
||||
render(<LoginWithGoogle />);
|
||||
render(<LoginWithGoogle redirectUrl={null} />);
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: /Continuer avec Google/i,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import "./login-with-google.css";
|
||||
import { useLoginGoogle } from "../../hooks/auth";
|
||||
|
||||
export function LoginWithGoogle() {
|
||||
const { loginWithGoogle } = useLoginGoogle();
|
||||
export function LoginWithGoogle({
|
||||
redirectUrl,
|
||||
}: {
|
||||
redirectUrl: string | null;
|
||||
}) {
|
||||
const { loginWithGoogle } = useLoginGoogle({ redirectUrl });
|
||||
|
||||
return (
|
||||
<button className="gsi-material-button" onClick={() => loginWithGoogle()}>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,15 @@ interface ProtectedRouteProps {
|
|||
fallback?: string;
|
||||
}
|
||||
|
||||
export const ProtectedRoute = ({ fallback }: ProtectedRouteProps) => {
|
||||
interface ProtectedRouteProps {
|
||||
fallback?: string;
|
||||
shouldRedirectToCurrentPage?: boolean;
|
||||
}
|
||||
|
||||
export const ProtectedRoute = ({
|
||||
fallback,
|
||||
shouldRedirectToCurrentPage,
|
||||
}: ProtectedRouteProps) => {
|
||||
const { session } = useSession();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
|
@ -38,14 +46,18 @@ export const ProtectedRoute = ({ fallback }: ProtectedRouteProps) => {
|
|||
status = "should-pass";
|
||||
}
|
||||
|
||||
const redirectUrl = shouldRedirectToCurrentPage
|
||||
? `${fallback ?? "/login"}?redirect=${encodeURIComponent(
|
||||
window.location.pathname
|
||||
)}`
|
||||
: fallback ?? "/login";
|
||||
|
||||
return (
|
||||
<>
|
||||
{match(status)
|
||||
.with("loading", () => <LoadingSpinner />)
|
||||
.with("should-land-user", () => <Navigate to="/landing" replace />)
|
||||
.with("should-redirect", () => (
|
||||
<Navigate to={fallback ?? "/login"} replace />
|
||||
))
|
||||
.with("should-redirect", () => <Navigate to={redirectUrl} replace />)
|
||||
.with("should-pass", () => <Outlet />)
|
||||
.exhaustive()}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ export function useSignUpToStream() {
|
|||
});
|
||||
return { signUpToStream };
|
||||
}
|
||||
export function useLoginEmail() {
|
||||
export function useLoginEmail({ redirectUrl }: { redirectUrl: string | null }) {
|
||||
const navigate = useNavigate();
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const { signUpToStream } = useSignUpToStream();
|
||||
|
|
@ -143,7 +143,11 @@ export function useLoginEmail() {
|
|||
return response;
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate("/");
|
||||
if (redirectUrl) {
|
||||
navigate(decodeURIComponent(redirectUrl));
|
||||
} else {
|
||||
navigate("/");
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
match(error.code)
|
||||
|
|
@ -168,13 +172,28 @@ export function useLoginEmail() {
|
|||
return { mutate, isPending, errors };
|
||||
}
|
||||
|
||||
export function useLoginGoogle() {
|
||||
export function useLoginGoogle({
|
||||
redirectUrl,
|
||||
}: {
|
||||
redirectUrl: string | null;
|
||||
}) {
|
||||
console.log({
|
||||
redirectTo: redirectUrl
|
||||
? `${
|
||||
window.location.origin
|
||||
}/login-with-oauth?redirect=${encodeURIComponent(redirectUrl)}`
|
||||
: `${window.location.origin}/login-with-oauth`,
|
||||
});
|
||||
const { mutate } = useMutation({
|
||||
mutationFn: async () => {
|
||||
const { data, error } = await supabase.auth.signInWithOAuth({
|
||||
provider: "google",
|
||||
options: {
|
||||
redirectTo: `${window.location.origin}/login-with-oauth`,
|
||||
redirectTo: redirectUrl
|
||||
? `${
|
||||
window.location.origin
|
||||
}/login-with-oauth?redirect=${encodeURIComponent(redirectUrl)}`
|
||||
: `${window.location.origin}/login-with-oauth`,
|
||||
},
|
||||
});
|
||||
if (error) throw error;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useParams, useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useUser } from "@ui/providers/UserStoreProvider";
|
||||
import { useJoinTablo } from "@ui/hooks/invite";
|
||||
import { toast } from "@ui/ui-library/toast/toast-queue";
|
||||
|
||||
export const JoinPage = () => {
|
||||
const { tablo_name } = useParams<{ tablo_name: string }>();
|
||||
|
|
@ -12,6 +13,20 @@ export const JoinPage = () => {
|
|||
const [searchParams] = useSearchParams();
|
||||
const token = searchParams.get("token");
|
||||
|
||||
if (!tablo_name || !token) {
|
||||
toast.add(
|
||||
{
|
||||
title: "Invitation invalide",
|
||||
description: "Veuillez vérifier le lien d'invitation",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
timeout: 2000,
|
||||
}
|
||||
);
|
||||
navigate("/");
|
||||
}
|
||||
|
||||
// const handleJoinTablo = async () => {
|
||||
// if (!user || !tablo_name || !token) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ import { Label, Input, TextField, FieldError } from "@ui/ui-library/field";
|
|||
import { useLoginEmail } from "@ui/hooks/auth";
|
||||
import { Form } from "@ui/ui-library/form";
|
||||
import { LoginWithGoogle } from "@ui/components/BrandButtons/LoginWithGoogle";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link, useSearchParams } from "react-router-dom";
|
||||
|
||||
export function LoginPage() {
|
||||
const { mutate: login, isPending, errors } = useLoginEmail();
|
||||
const [searchParams] = useSearchParams();
|
||||
const redirectUrl = searchParams.get("redirect");
|
||||
|
||||
const { mutate: login, isPending, errors } = useLoginEmail({ redirectUrl });
|
||||
const [formData, setFormData] = useState({
|
||||
email: "",
|
||||
password: "",
|
||||
|
|
@ -113,7 +116,7 @@ export function LoginPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<LoginWithGoogle />
|
||||
<LoginWithGoogle redirectUrl={redirectUrl} />
|
||||
|
||||
<p className="text-center text-sm text-slate-600 dark:text-slate-400">
|
||||
Pas encore de compte ?{" "}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useSession } from "@ui/contexts/SessionContext";
|
||||
import { useSignUpToStream } from "@ui/hooks/auth";
|
||||
|
||||
|
|
@ -7,11 +7,17 @@ export const OAuthSigninPage = () => {
|
|||
const navigate = useNavigate();
|
||||
const { session } = useSession();
|
||||
const { signUpToStream } = useSignUpToStream();
|
||||
const [searchParams] = useSearchParams();
|
||||
const redirectUrl = searchParams.get("redirect");
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
if (session) {
|
||||
signUpToStream(session.access_token);
|
||||
navigate("/");
|
||||
if (redirectUrl) {
|
||||
navigate(decodeURIComponent(redirectUrl));
|
||||
} else {
|
||||
navigate("/");
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
return () => clearInterval(interval);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Button } from "@ui/ui-library/button";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Link, useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
import { Label, Input, TextField, FieldError } from "@ui/ui-library/field";
|
||||
import { useSignUp } from "@ui/hooks/auth";
|
||||
|
|
@ -10,6 +10,8 @@ import { LoginWithGoogle } from "@ui/components/BrandButtons/LoginWithGoogle";
|
|||
|
||||
export function SignUpPage() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const redirectUrl = searchParams.get("redirect");
|
||||
const { mutate: signUp, isPending } = useSignUp();
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
|
|
@ -246,7 +248,7 @@ export function SignUpPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<LoginWithGoogle />
|
||||
<LoginWithGoogle redirectUrl={redirectUrl} />
|
||||
|
||||
<p className="text-center text-sm text-slate-600 dark:text-slate-400">
|
||||
Déjà un compte ?{" "}
|
||||
|
|
|
|||
Loading…
Reference in a new issue