✨ feat: create provider callback handler
This commit is contained in:
@ -1,20 +1,7 @@
|
||||
import React from "react";
|
||||
import AuthCallbackIndex from "@/features/authCallback";
|
||||
|
||||
const page = async ({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { name: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
}) => {
|
||||
const resolvedParams = await params;
|
||||
const resolvedSearchParams = await searchParams;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Loading....</h1>
|
||||
</div>
|
||||
);
|
||||
const page = async () => {
|
||||
return <AuthCallbackIndex />;
|
||||
};
|
||||
|
||||
export default page;
|
||||
|
||||
3
bun.lock
3
bun.lock
@ -16,6 +16,7 @@
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"shadcn": "^3.6.3",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
},
|
||||
@ -1276,6 +1277,8 @@
|
||||
|
||||
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||
|
||||
"sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
40
features/authCallback/index.tsx
Normal file
40
features/authCallback/index.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
"use client";
|
||||
import { Spinner } from "@/shared/libs/shadcn/ui/spinner";
|
||||
import { submitProviderCallback } from "@/shared/widgets/signin/actions/submitProviderCallback";
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const AuthCallbackIndex = () => {
|
||||
const { name } = useParams();
|
||||
const queries = useSearchParams().toString();
|
||||
const router = useRouter();
|
||||
const [textDescription, setTextDescription] = useState(
|
||||
"We are processing your authentication."
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const response = await submitProviderCallback(name as string, queries);
|
||||
if (response.success) {
|
||||
setTextDescription("Authentication successful! Redirecting...");
|
||||
router.push("/");
|
||||
} else {
|
||||
setTextDescription("Authentication failed. Please try again.");
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-col items-center gap-2 pt-8">
|
||||
<Spinner className="size-6" />
|
||||
<div className="text-center">
|
||||
<h1 className="text-neutral-200 text-base">Please wait...</h1>
|
||||
<p className="font-normal text-neutral-400 text-sm">
|
||||
{textDescription}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthCallbackIndex;
|
||||
@ -20,6 +20,7 @@
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"shadcn": "^3.6.3",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
},
|
||||
|
||||
49
shared/libs/shadcn/ui/sonner.tsx
Normal file
49
shared/libs/shadcn/ui/sonner.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
"use client"
|
||||
|
||||
import { useTheme } from "next-themes"
|
||||
import { Toaster as Sonner, type ToasterProps } from "sonner"
|
||||
import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
|
||||
|
||||
const Toaster = ({ ...props }: ToasterProps) => {
|
||||
const { theme = "system" } = useTheme()
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
className="toaster group"
|
||||
icons={{
|
||||
success: (
|
||||
<CircleCheckIcon className="size-4" />
|
||||
),
|
||||
info: (
|
||||
<InfoIcon className="size-4" />
|
||||
),
|
||||
warning: (
|
||||
<TriangleAlertIcon className="size-4" />
|
||||
),
|
||||
error: (
|
||||
<OctagonXIcon className="size-4" />
|
||||
),
|
||||
loading: (
|
||||
<Loader2Icon className="size-4 animate-spin" />
|
||||
),
|
||||
}}
|
||||
style={
|
||||
{
|
||||
"--normal-bg": "var(--popover)",
|
||||
"--normal-text": "var(--popover-foreground)",
|
||||
"--normal-border": "var(--border)",
|
||||
"--border-radius": "var(--radius)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast: "cn-toast",
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Toaster }
|
||||
54
shared/widgets/signin/actions/submitProviderCallback.ts
Normal file
54
shared/widgets/signin/actions/submitProviderCallback.ts
Normal file
@ -0,0 +1,54 @@
|
||||
"use server";
|
||||
|
||||
import { backendFetch, BackendResponse } from "@/shared/helper/backendFetch";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const submitProviderCallback = async (
|
||||
providerName: string,
|
||||
queries?: unknown
|
||||
): Promise<
|
||||
BackendResponse<{
|
||||
authToken: string;
|
||||
}>
|
||||
> => {
|
||||
try {
|
||||
const envKey = providerName.toUpperCase() + "_CALLBACK_URL";
|
||||
|
||||
const authClientCallbackUrl = (await backendFetch(
|
||||
"auth/providers/" + providerName + "/callback"
|
||||
)) as BackendResponse<{
|
||||
callback_url: string;
|
||||
}>;
|
||||
|
||||
if (!authClientCallbackUrl.success)
|
||||
throw new Error("Failed to get auth client callback URL");
|
||||
|
||||
const responseProvision = (await backendFetch(
|
||||
`${authClientCallbackUrl.data?.callback_url!}?callbackURI=${
|
||||
process.env.APP_URL
|
||||
}${process.env[envKey]}&${queries}`
|
||||
)) as BackendResponse<{
|
||||
authToken: string;
|
||||
}>;
|
||||
|
||||
if (!responseProvision.success)
|
||||
throw new Error("Failed to submit provider callback");
|
||||
|
||||
(await cookies()).set({
|
||||
name: "auth_token",
|
||||
value: responseProvision.data?.authToken!,
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
maxAge: Number(process.env.SESSION_EXPIRE),
|
||||
});
|
||||
|
||||
return responseProvision;
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
message: "Error submitting provider callback",
|
||||
error: error,
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user