Skip to content

Commit

Permalink
Merge pull request #1299 from Shelf-nu/fix-resend-otp
Browse files Browse the repository at this point in the history
fix: otp ux and resending
  • Loading branch information
DonKoko authored Sep 3, 2024
2 parents b0a1f5f + 6d6d2d1 commit 897b228
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
7 changes: 5 additions & 2 deletions app/modules/auth/service.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,15 @@ export async function resendVerificationEmail(email: string) {
throw error;
}
} catch (cause) {
// @ts-expect-error
const isRateLimitError = cause?.code === "over_email_send_rate_limit";
throw new ShelfError({
cause,
message:
"Something went wrong while resending the verification email. Please try again later or contact support.",
additionalData: { email },
label,
shouldBeCaptured: !isRateLimitError,
});
}
}
Expand Down Expand Up @@ -181,8 +184,8 @@ export async function sendOTP(email: string) {
throw error;
}
} catch (cause) {
const isRateLimitError =
cause instanceof AuthError && cause.code === "over_email_send_rate_limit";
// @ts-expect-error
const isRateLimitError = cause.code === "over_email_send_rate_limit";
throw new ShelfError({
cause,
message:
Expand Down
54 changes: 30 additions & 24 deletions app/routes/_auth+/otp.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import type {
ActionFunctionArgs,
LoaderFunctionArgs,
MetaFunction,
} from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { useActionData, useNavigation } from "@remix-run/react";
import { useActionData, useFetcher } from "@remix-run/react";
import { useZorm } from "react-zorm";
import { z } from "zod";
import { Form } from "~/components/custom-form";
Expand All @@ -20,7 +20,6 @@ import { appendToMetaTitle } from "~/utils/append-to-meta-title";
import { setCookie } from "~/utils/cookies.server";
import { makeShelfError, notAllowedMethod } from "~/utils/error";
import { isFormProcessing } from "~/utils/form";
import { isErrorResponse } from "~/utils/http";
import {
data,
error,
Expand All @@ -32,6 +31,7 @@ import { validEmail } from "~/utils/misc";
import { getOtpPageData, type OtpVerifyMode } from "~/utils/otp";
import { tw } from "~/utils/tw";
import { randomUsernameFromEmail } from "~/utils/user";
import type { action as resendOtpAction } from "./resend-otp";

export function loader({ context, request }: LoaderFunctionArgs) {
const { searchParams } = new URL(request.url);
Expand Down Expand Up @@ -105,54 +105,58 @@ export const meta: MetaFunction<typeof loader> = ({ data }) => [
{ title: data ? appendToMetaTitle(data.title) : "" },
];

type resendAction = typeof resendOtpAction;

export default function OtpPage() {
const [message, setMessage] = useState<{
message: string;
type: "success" | "error";
}>();
const data = useActionData<typeof action>();
const [searchParams] = useSearchParams();
const fetcher = useFetcher<resendAction>();

const zo = useZorm("otpForm", OtpSchema);
const transition = useNavigation();
const disabled = isFormProcessing(transition.state);
const disabled = isFormProcessing(fetcher.state);

const email = searchParams.get("email") || "";
const mode = searchParams.get("mode") as OtpVerifyMode;
const pageData = getOtpPageData(mode);

async function handleResendOtp() {
function handleResendOtp() {
const formData = new FormData();
formData.append("email", email);
formData.append("mode", mode);

try {
const response = await fetch("/send-otp", {
method: "post",
body: formData,
fetcher.submit(formData, {
method: "POST",
action: "/resend-otp",
});
} catch {
setMessage({
message: "Something went wrong. Please try again.",
type: "error",
});
}
}

if (response.status === 200) {
/** Handle success and error state when resending with fetcher */
useEffect(() => {
if (fetcher?.data) {
if (fetcher.data.error) {
setMessage({
message: "Email sent successfully. Please check your inbox.",
type: "success",
message: fetcher.data.error.message,
type: "error",
});
} else {
const data = await response.json();
setMessage({
message: isErrorResponse(data)
? data.error.message
: "Something went wrong. Please try again!",
type: "error",
message: "Email sent successfully. Please check your inbox.",
type: "success",
});
}
} catch {
setMessage({
message: "Something went wrong. Please try again.",
type: "error",
});
}
}
}, [fetcher]);

return (
<>
Expand Down Expand Up @@ -201,7 +205,9 @@ export default function OtpPage() {
onClick={handleResendOtp}
>
Did not receive a code?{" "}
<span className="text-primary-500">Send again</span>
<span className="text-primary-500">
{disabled ? "Sending code..." : "Send again"}
</span>
</button>
</div>
</div>
Expand Down
7 changes: 4 additions & 3 deletions app/routes/_auth+/resend-otp.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { z } from "zod";
import { resendVerificationEmail } from "~/modules/auth/service.server";
import { sendOTP } from "~/modules/auth/service.server";
import { makeShelfError, notAllowedMethod } from "~/utils/error";

import { error, getActionMethod, parseData } from "~/utils/http.server";
import { data, error, getActionMethod, parseData } from "~/utils/http.server";
import { validEmail } from "~/utils/misc";

export async function action({ request }: ActionFunctionArgs) {
Expand All @@ -25,7 +25,8 @@ export async function action({ request }: ActionFunctionArgs) {
})
);

await resendVerificationEmail(email);
await sendOTP(email);
return json(data({ success: true }));
}
}

Expand Down

0 comments on commit 897b228

Please sign in to comment.