add sign in with password
This commit is contained in:
parent
741c44ebe5
commit
08ee186737
|
@ -9,7 +9,7 @@ import Link from "next/link";
|
|||
import { FormField } from "@/app/_components/form-field";
|
||||
// import { useSignInController } from "@/src/interface-adapters/controllers/auth/sign-in.controller";
|
||||
import { useState } from "react";
|
||||
import { signIn } from "../action";
|
||||
|
||||
import { useSignInHandler } from "../_handlers/use-sign-in";
|
||||
|
||||
export function SignInForm({
|
||||
|
@ -98,7 +98,7 @@ export function SignInForm({
|
|||
{isPending ? (
|
||||
<>
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
Signing in...
|
||||
Sign in
|
||||
</>
|
||||
) : (
|
||||
"Sign in"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { useSignInMutation } from "../_queries/mutations";
|
||||
import { useSignInPasswordlessMutation } from "../_queries/mutations";
|
||||
import { toast } from "sonner";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
@ -7,7 +7,7 @@ import { ISignInPasswordlessSchema, SignInPasswordlessSchema } from "@/src/entit
|
|||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
export function useSignInHandler() {
|
||||
const { mutateAsync: signIn, isPending, error: errors } = useSignInMutation();
|
||||
const { mutateAsync: signIn, isPending, error: errors } = useSignInPasswordlessMutation();
|
||||
const { router } = useNavigations();
|
||||
|
||||
const [error, setError] = useState<string>();
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import { useMutation } from "@tanstack/react-query"
|
||||
import { sendMagicLink, sendPasswordRecovery, signIn, signOut, verifyOtp } from "../action"
|
||||
import { sendMagicLink, sendPasswordRecovery, signInPasswordless, signInWithPassword, signOut, verifyOtp } from "../action"
|
||||
|
||||
export const useSignInMutation = () => {
|
||||
export const useSignInPasswordlessMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["signIn"],
|
||||
mutationFn: async (formData: FormData) => await signIn(formData),
|
||||
mutationFn: async (formData: FormData) => await signInPasswordless(formData),
|
||||
})
|
||||
}
|
||||
|
||||
export const useSignInWithPasswordMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["signInWithCredentials"],
|
||||
mutationFn: async (formData: FormData) => await signInWithPassword(formData),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,17 +8,18 @@ import { InputParseError, NotFoundError } from "@/src/entities/errors/common"
|
|||
import { AuthenticationError, UnauthenticatedError } from "@/src/entities/errors/auth"
|
||||
import { createClient } from "@/app/_utils/supabase/server"
|
||||
|
||||
export async function signIn(formData: FormData) {
|
||||
export async function signInPasswordless(formData: FormData) {
|
||||
const instrumentationService = getInjection("IInstrumentationService")
|
||||
return await instrumentationService.instrumentServerAction("signIn", {
|
||||
recordResponse: true
|
||||
},
|
||||
async () => {
|
||||
const email = formData.get("email")?.toString()
|
||||
|
||||
try {
|
||||
const signInController = getInjection("ISignInController")
|
||||
return await signInController({ email })
|
||||
const email = formData.get("email")?.toString()
|
||||
|
||||
const signInPasswordlessController = getInjection("ISignInPasswordlessController")
|
||||
return await signInPasswordlessController({ email })
|
||||
|
||||
// if (email) {
|
||||
// redirect(`/verify-otp?email=${encodeURIComponent(email)}`)
|
||||
|
@ -51,6 +52,43 @@ export async function signIn(formData: FormData) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
export async function signInWithPassword(formData: FormData) {
|
||||
const instrumentationService = getInjection("IInstrumentationService")
|
||||
return await instrumentationService.instrumentServerAction("signInWithPassword", {
|
||||
recordResponse: true
|
||||
}, async () => {
|
||||
try {
|
||||
const email = formData.get("email")?.toString()
|
||||
const password = formData.get("password")?.toString()
|
||||
|
||||
const signInWithPasswordController = getInjection("ISignInWithPasswordController")
|
||||
return await signInWithPasswordController({ email, password })
|
||||
} catch (err) {
|
||||
if (err instanceof InputParseError) {
|
||||
return { error: err.message }
|
||||
}
|
||||
|
||||
if (err instanceof AuthenticationError) {
|
||||
return { error: "Invalid credential. Please try again." }
|
||||
}
|
||||
|
||||
if (err instanceof UnauthenticatedError || err instanceof NotFoundError) {
|
||||
return {
|
||||
error: 'User not found. Please tell your admin to create an account for you.',
|
||||
};
|
||||
}
|
||||
|
||||
const crashReporterService = getInjection('ICrashReporterService');
|
||||
crashReporterService.report(err);
|
||||
|
||||
return {
|
||||
error:
|
||||
'An error happened. The developers have been notified. Please try again later.',
|
||||
};
|
||||
}
|
||||
})
|
||||
}
|
||||
// export async function signUp(formData: FormData) {
|
||||
// const instrumentationService = getInjection("IInstrumentationService")
|
||||
// return await instrumentationService.instrumentServerAction("signUp", { recordResponse: true }, async () => {
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
// import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||
// import { useState } from "react";
|
||||
// import { useAuthActions } from './queries';
|
||||
// import { useForm } from 'react-hook-form';
|
||||
// import { zodResolver } from '@hookform/resolvers/zod';;
|
||||
// import { toast } from 'sonner';
|
||||
// import { useNavigations } from '@/app/_hooks/use-navigations';
|
||||
// import {
|
||||
// IVerifyOtpSchema,
|
||||
// verifyOtpSchema,
|
||||
// } from '@/src/entities/models/auth/verify-otp.model';
|
||||
|
||||
// /**
|
||||
// * Hook untuk menangani proses sign in
|
||||
// *
|
||||
// * @returns {Object} Object berisi handler dan state untuk form sign in
|
||||
// * @example
|
||||
// * const { handleSubmit, isPending, error } = useSignInHandler();
|
||||
// * <form onSubmit={handleSubmit}>...</form>
|
||||
// */
|
||||
// export function useSignInHandler() {
|
||||
// const { signIn } = useAuthActions();
|
||||
// const { router } = useNavigations();
|
||||
|
||||
// const [error, setError] = useState<string>();
|
||||
|
||||
// const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
// event.preventDefault();
|
||||
// if (signIn.isPending) return;
|
||||
|
||||
// setError(undefined);
|
||||
|
||||
// const formData = new FormData(event.currentTarget);
|
||||
// const email = formData.get('email')?.toString();
|
||||
|
||||
// const res = await signIn.mutateAsync(formData);
|
||||
|
||||
// if (!res?.error) {
|
||||
// toast('An email has been sent to you. Please check your inbox.');
|
||||
// if (email) router.push(`/verify-otp?email=${encodeURIComponent(email)}`);
|
||||
// } else {
|
||||
// setError(res.error);
|
||||
// }
|
||||
|
||||
|
||||
// };
|
||||
|
||||
// return {
|
||||
// // formData,
|
||||
// // handleChange,
|
||||
// handleSignIn: handleSubmit,
|
||||
// error,
|
||||
// isPending: signIn.isPending,
|
||||
// errors: !!error || signIn.error,
|
||||
// clearError: () => setError(undefined),
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function useVerifyOtpHandler(email: string) {
|
||||
// const { router } = useNavigations();
|
||||
// const { verifyOtp } = useAuthActions();
|
||||
// const [error, setError] = useState<string>();
|
||||
|
||||
// const {
|
||||
// register,
|
||||
// handleSubmit: hookFormSubmit,
|
||||
// control,
|
||||
// formState: { errors },
|
||||
// setValue,
|
||||
// } = useForm<IVerifyOtpSchema>({
|
||||
// resolver: zodResolver(verifyOtpSchema),
|
||||
// defaultValues: {
|
||||
// email,
|
||||
// token: '',
|
||||
// },
|
||||
// });
|
||||
|
||||
// const handleOtpChange = (
|
||||
// value: string,
|
||||
// onChange: (value: string) => void
|
||||
// ) => {
|
||||
// onChange(value);
|
||||
|
||||
// if (value.length === 6) {
|
||||
// handleSubmit();
|
||||
// }
|
||||
|
||||
// // Clear error when user starts typing
|
||||
// if (error) {
|
||||
// setError(undefined);
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handleSubmit = hookFormSubmit(async (data) => {
|
||||
// if (verifyOtp.isPending) return;
|
||||
|
||||
// setError(undefined);
|
||||
|
||||
// // Create FormData object
|
||||
// const formData = new FormData();
|
||||
// formData.append('email', data.email);
|
||||
// formData.append('token', data.token);
|
||||
|
||||
// await verifyOtp.mutateAsync(formData, {
|
||||
// onSuccess: () => {
|
||||
// toast.success('OTP verified successfully');
|
||||
// // Navigate to dashboard on success
|
||||
// router.push('/dashboard');
|
||||
// },
|
||||
// onError: (error) => {
|
||||
// setError(error.message);
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// return {
|
||||
// register,
|
||||
// control,
|
||||
// handleVerifyOtp: handleSubmit,
|
||||
// handleOtpChange,
|
||||
// errors: {
|
||||
// ...errors,
|
||||
// token: error ? { message: error } : errors.token,
|
||||
// },
|
||||
// isPending: verifyOtp.isPending,
|
||||
// clearError: () => setError(undefined),
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function useSignOutHandler() {
|
||||
// const { signOut } = useAuthActions();
|
||||
// const { router } = useNavigations();
|
||||
// const [error, setError] = useState<string>();
|
||||
|
||||
// const handleSignOut = async () => {
|
||||
// if (signOut.isPending) return;
|
||||
|
||||
// setError(undefined);
|
||||
|
||||
// await signOut.mutateAsync(undefined, {
|
||||
// onSuccess: () => {
|
||||
// toast.success('You have been signed out successfully');
|
||||
// router.push('/sign-in');
|
||||
// },
|
||||
// onError: (error) => {
|
||||
// if (error instanceof AuthenticationError) {
|
||||
// setError(error.message);
|
||||
// toast.error(error.message);
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
// };
|
||||
|
||||
// return {
|
||||
// handleSignOut,
|
||||
// error,
|
||||
// isPending: signOut.isPending,
|
||||
// errors: !!error || signOut.error,
|
||||
// clearError: () => setError(undefined),
|
||||
// };
|
||||
// }
|
|
@ -0,0 +1,50 @@
|
|||
import { Carousel, CarouselContent, CarouselItem } from "@/app/_components/ui/carousal"
|
||||
import { QuoteIcon } from "lucide-react"
|
||||
|
||||
export const CarousalQuotes = () => {
|
||||
|
||||
const items = [
|
||||
{
|
||||
quote: "Tried @supabase for the first time yesterday. Amazing tool! I was able to get my Posgres DB up in no time and their documentation on operating on the DB is super easy! 👏 Can't wait for Cloud functions to arrive! It's gonna be a great Firebase alternative!",
|
||||
author: "@codewithbhargav",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
{
|
||||
quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
|
||||
author: "@techenthusiast",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
{
|
||||
quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
|
||||
author: "@dataguru",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Carousel showDots autoPlay autoPlayInterval={10000} className="w-full max-w-md" >
|
||||
<CarouselContent className="py-8">
|
||||
{items.map((item, index) => (
|
||||
<CarouselItem key={index} className="flex flex-col items-center justify-center">
|
||||
<div className="relative flex flex-col items-start text-start">
|
||||
{/* <QuoteIcon className="absolute h-20 w-20 text-muted opacity-80 -z-10 top-[-30px] transform rotate-180 " /> */}
|
||||
<h2 className="text-3xl font-medium text-white mb-8">{item.quote}</h2>
|
||||
<div className="flex items-center gap-4">
|
||||
<img
|
||||
src={item.image}
|
||||
alt="Profile"
|
||||
className="w-12 h-12 rounded-full"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-white font-medium">{item.author}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -2,25 +2,9 @@ import { SignInForm } from "@/app/(pages)/(auth)/_components/signin-form";
|
|||
import { Message } from "@/app/_components/form-message";
|
||||
import { Button } from "@/app/_components/ui/button";
|
||||
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/app/_components/ui/carousal";
|
||||
import { IconQuoteFilled } from "@tabler/icons-react";
|
||||
import { GalleryVerticalEnd, Globe, QuoteIcon } from "lucide-react";
|
||||
|
||||
const carouselContent = [
|
||||
{
|
||||
quote: "Tried @supabase for the first time yesterday. Amazing tool! I was able to get my Posgres DB up in no time and their documentation on operating on the DB is super easy! 👏 Can't wait for Cloud functions to arrive! It's gonna be a great Firebase alternative!",
|
||||
author: "@codewithbhargav",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
{
|
||||
quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
|
||||
author: "@techenthusiast",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
{
|
||||
quote: "Check out this amazing product @supabase. A must give try #newidea #opportunity",
|
||||
author: "@dataguru",
|
||||
image: "https://github.com/shadcn.png",
|
||||
},
|
||||
];
|
||||
import { CarousalQuotes } from "./_components/carousal-quote";
|
||||
|
||||
export default async function Login(props: { searchParams: Promise<Message> }) {
|
||||
return (
|
||||
|
@ -49,28 +33,7 @@ export default async function Login(props: { searchParams: Promise<Message> }) {
|
|||
<Globe className="mr-0 h-4 w-4" />
|
||||
Showcase
|
||||
</Button>
|
||||
<Carousel showDots autoPlay autoPlayInterval={10000} className="w-full max-w-md" >
|
||||
<CarouselContent className="py-8">
|
||||
{carouselContent.map((item, index) => (
|
||||
<CarouselItem key={index} className="flex flex-col items-center justify-center">
|
||||
<div className="relative flex flex-col items-start text-start">
|
||||
<QuoteIcon className="absolute h-20 w-20 text-primary opacity-10 -z-10 top-[-30px] transform rotate-180 " />
|
||||
<h2 className="text-3xl font-medium text-white mb-8">{item.quote}</h2>
|
||||
<div className="flex items-center gap-4">
|
||||
<img
|
||||
src={item.image}
|
||||
alt="Profile"
|
||||
className="w-12 h-12 rounded-full"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-white font-medium">{item.author}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
<CarousalQuotes />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,12 +2,12 @@ import { createModule } from '@evyweb/ioctopus';
|
|||
|
||||
import { AuthenticationService } from '@/src/infrastructure/services/authentication.service';
|
||||
|
||||
import { signInUseCase } from '@/src/application/use-cases/auth/sign-in.use-case';
|
||||
import { signInUseCase } from '@/src/application/use-cases/auth/sign-in-passwordless.use-case';
|
||||
import { signUpUseCase } from '@/src/application/use-cases/auth/sign-up.use-case';
|
||||
import { signOutUseCase } from '@/src/application/use-cases/auth/sign-out.use-case';
|
||||
|
||||
import { DI_SYMBOLS } from '@/di/types';
|
||||
import { signInController } from '@/src/interface-adapters/controllers/auth/sign-in.controller';
|
||||
import { signInPasswordlessController } from '@/src/interface-adapters/controllers/auth/sign-in-passwordless.controller';
|
||||
import { signOutController } from '@/src/interface-adapters/controllers/auth/sign-out.controller';
|
||||
import { verifyOtpUseCase } from '@/src/application/use-cases/auth/verify-otp.use-case';
|
||||
import { verifyOtpController } from '@/src/interface-adapters/controllers/auth/verify-otp.controller';
|
||||
|
@ -15,6 +15,8 @@ import { sendMagicLinkUseCase } from '@/src/application/use-cases/auth/send-magi
|
|||
import { sendPasswordRecoveryUseCase } from '@/src/application/use-cases/auth/send-password-recovery.use-case';
|
||||
import { sendMagicLinkController } from '@/src/interface-adapters/controllers/auth/send-magic-link.controller';
|
||||
import { sendPasswordRecoveryController } from '@/src/interface-adapters/controllers/auth/send-password-recovery.controller';
|
||||
import { signInWithPasswordUseCase } from '@/src/application/use-cases/auth/sign-in-with-password.use-case';
|
||||
import { signInWithPasswordController } from '@/src/interface-adapters/controllers/auth/sign-in-with-password.controller';
|
||||
|
||||
export function createAuthenticationModule() {
|
||||
const authenticationModule = createModule();
|
||||
|
@ -40,13 +42,21 @@ export function createAuthenticationModule() {
|
|||
|
||||
// Use Cases
|
||||
authenticationModule
|
||||
.bind(DI_SYMBOLS.ISignInUseCase)
|
||||
.bind(DI_SYMBOLS.ISignInPasswordlessUseCase)
|
||||
.toHigherOrderFunction(signInUseCase, [
|
||||
DI_SYMBOLS.IInstrumentationService,
|
||||
DI_SYMBOLS.IAuthenticationService,
|
||||
DI_SYMBOLS.IUsersRepository,
|
||||
]);
|
||||
|
||||
authenticationModule
|
||||
.bind(DI_SYMBOLS.ISignInWithPasswordUseCase)
|
||||
.toHigherOrderFunction(signInWithPasswordUseCase, [
|
||||
DI_SYMBOLS.IInstrumentationService,
|
||||
DI_SYMBOLS.IAuthenticationService,
|
||||
DI_SYMBOLS.IUsersRepository,
|
||||
]);
|
||||
|
||||
authenticationModule
|
||||
.bind(DI_SYMBOLS.ISignUpUseCase)
|
||||
.toHigherOrderFunction(signUpUseCase, [
|
||||
|
@ -89,10 +99,17 @@ export function createAuthenticationModule() {
|
|||
|
||||
// Controllers
|
||||
authenticationModule
|
||||
.bind(DI_SYMBOLS.ISignInController)
|
||||
.toHigherOrderFunction(signInController, [
|
||||
.bind(DI_SYMBOLS.ISignInPasswordlessController)
|
||||
.toHigherOrderFunction(signInPasswordlessController, [
|
||||
DI_SYMBOLS.IInstrumentationService,
|
||||
DI_SYMBOLS.ISignInUseCase,
|
||||
DI_SYMBOLS.ISignInPasswordlessUseCase,
|
||||
]);
|
||||
|
||||
authenticationModule
|
||||
.bind(DI_SYMBOLS.ISignInWithPasswordController)
|
||||
.toHigherOrderFunction(signInWithPasswordController, [
|
||||
DI_SYMBOLS.IInstrumentationService,
|
||||
DI_SYMBOLS.ISignInWithPasswordUseCase,
|
||||
]);
|
||||
|
||||
authenticationModule
|
||||
|
|
|
@ -3,12 +3,12 @@ import { ITransactionManagerService } from '@/src/application/services/transacti
|
|||
import { IInstrumentationService } from '@/src/application/services/instrumentation.service.interface';
|
||||
import { ICrashReporterService } from '@/src/application/services/crash-reporter.service.interface';
|
||||
|
||||
import { ISignInUseCase } from '@/src/application/use-cases/auth/sign-in.use-case';
|
||||
import { ISignInPasswordlessUseCase } from '@/src/application/use-cases/auth/sign-in-passwordless.use-case';
|
||||
import { ISignUpUseCase } from '@/src/application/use-cases/auth/sign-up.use-case';
|
||||
import { ISignOutUseCase } from '@/src/application/use-cases/auth/sign-out.use-case';
|
||||
import { IUsersRepository } from '@/src/application/repositories/users.repository.interface';
|
||||
import { IVerifyOtpUseCase } from '@/src/application/use-cases/auth/verify-otp.use-case';
|
||||
import { ISignInController } from '@/src/interface-adapters/controllers/auth/sign-in.controller';
|
||||
import { ISignInPasswordlessController } from '@/src/interface-adapters/controllers/auth/sign-in-passwordless.controller';
|
||||
import { ISignOutController } from '@/src/interface-adapters/controllers/auth/sign-out.controller';
|
||||
import { IVerifyOtpController } from '@/src/interface-adapters/controllers/auth/verify-otp.controller';
|
||||
import { IBanUserUseCase } from '@/src/application/use-cases/users/ban-user.use-case';
|
||||
|
@ -39,6 +39,7 @@ import { ISendMagicLinkController } from '@/src/interface-adapters/controllers/a
|
|||
import { ISendPasswordRecoveryController } from '@/src/interface-adapters/controllers/auth/send-password-recovery.controller';
|
||||
import { IUploadAvatarController } from '@/src/interface-adapters/controllers/users/upload-avatar.controller';
|
||||
import { IUploadAvatarUseCase } from '@/src/application/use-cases/users/upload-avatar.use-case';
|
||||
import { ISignInWithPasswordController } from '@/src/interface-adapters/controllers/auth/sign-in-with-password.controller';
|
||||
|
||||
export const DI_SYMBOLS = {
|
||||
// Services
|
||||
|
@ -51,7 +52,8 @@ export const DI_SYMBOLS = {
|
|||
IUsersRepository: Symbol.for('IUsersRepository'),
|
||||
|
||||
// Use Cases
|
||||
ISignInUseCase: Symbol.for('ISignInUseCase'),
|
||||
ISignInPasswordlessUseCase: Symbol.for('ISignInPasswordlessUseCase'),
|
||||
ISignInWithPasswordUseCase: Symbol.for('ISignInWithPasswordUseCase'),
|
||||
ISignUpUseCase: Symbol.for('ISignUpUseCase'),
|
||||
IVerifyOtpUseCase: Symbol.for('IVerifyOtpUseCase'),
|
||||
ISignOutUseCase: Symbol.for('ISignOutUseCase'),
|
||||
|
@ -72,7 +74,8 @@ export const DI_SYMBOLS = {
|
|||
IUploadAvatarUseCase: Symbol.for('IUploadAvatarUseCase'),
|
||||
|
||||
// Controllers
|
||||
ISignInController: Symbol.for('ISignInController'),
|
||||
ISignInPasswordlessController: Symbol.for('ISignInPasswordlessController'),
|
||||
ISignInWithPasswordController: Symbol.for('ISignInWithPasswordController'),
|
||||
ISignOutController: Symbol.for('ISignOutController'),
|
||||
IVerifyOtpController: Symbol.for('IVerifyOtpController'),
|
||||
ISendMagicLinkController: Symbol.for('ISendMagicLinkController'),
|
||||
|
@ -103,7 +106,7 @@ export interface DI_RETURN_TYPES {
|
|||
IUsersRepository: IUsersRepository;
|
||||
|
||||
// Use Cases
|
||||
ISignInUseCase: ISignInUseCase;
|
||||
ISignInPasswordlessUseCase: ISignInPasswordlessUseCase;
|
||||
ISignUpUseCase: ISignUpUseCase;
|
||||
IVerifyOtpUseCase: IVerifyOtpUseCase;
|
||||
ISignOutUseCase: ISignOutUseCase;
|
||||
|
@ -124,7 +127,8 @@ export interface DI_RETURN_TYPES {
|
|||
IUploadAvatarUseCase: IUploadAvatarUseCase;
|
||||
|
||||
// Controllers
|
||||
ISignInController: ISignInController;
|
||||
ISignInPasswordlessController: ISignInPasswordlessController;
|
||||
ISignInWithPasswordController: ISignInWithPasswordController;
|
||||
IVerifyOtpController: IVerifyOtpController;
|
||||
ISignOutController: ISignOutController;
|
||||
ISendMagicLinkController: ISendMagicLinkController;
|
||||
|
|
|
@ -9,9 +9,9 @@ import { IUserSchema } from "@/src/entities/models/users/users.model"
|
|||
|
||||
export interface IAuthenticationService {
|
||||
signInPasswordless(credentials: ISignInPasswordlessSchema): Promise<void>
|
||||
SignInWithPasswordSchema(credentials: ISignInWithPasswordSchema): Promise<void>
|
||||
SignUpWithEmailSchema(credentials: ISignUpWithEmailSchema): Promise<IUserSchema>
|
||||
SignUpWithPhoneSchema(credentials: ISignUpWithPhoneSchema): Promise<IUserSchema>
|
||||
signInWithPassword(credentials: ISignInWithPasswordSchema): Promise<void>
|
||||
SignUpWithEmail(credentials: ISignUpWithEmailSchema): Promise<IUserSchema>
|
||||
SignUpWithPhone(credentials: ISignUpWithPhoneSchema): Promise<IUserSchema>
|
||||
getSession(): Promise<Session | null>
|
||||
signOut(): Promise<void>
|
||||
sendMagicLink(credentials: ISendMagicLinkSchema): Promise<void>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { type TSignInSchema, ISignInPasswordlessSchema, SignInSchema } from "@/s
|
|||
import { IAuthenticationService } from "@/src/application/services/authentication.service.interface";
|
||||
import { IUsersRepository } from "../../repositories/users.repository.interface";
|
||||
|
||||
export type ISignInUseCase = ReturnType<typeof signInUseCase>
|
||||
export type ISignInPasswordlessUseCase = ReturnType<typeof signInUseCase>
|
||||
|
||||
export const signInUseCase =
|
||||
(
|
|
@ -0,0 +1,27 @@
|
|||
import { UnauthenticatedError } from "@/src/entities/errors/auth";
|
||||
import { IUsersRepository } from "../../repositories/users.repository.interface";
|
||||
import { IAuthenticationService } from "../../services/authentication.service.interface";
|
||||
import { IInstrumentationService } from "../../services/instrumentation.service.interface";
|
||||
|
||||
export type ISignInWithPasswordUseCase = ReturnType<typeof signInWithPasswordUseCase>
|
||||
|
||||
export const signInWithPasswordUseCase = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
authenticationService: IAuthenticationService,
|
||||
usersRepository: IUsersRepository
|
||||
) => async (input: { email: string; password: string }): Promise<void> => {
|
||||
return await instrumentationService.startSpan({ name: "signInWithPassword Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
const existingUser = await usersRepository.getUserByEmail({ email: input.email })
|
||||
|
||||
if (!existingUser) {
|
||||
throw new UnauthenticatedError("User not found. Please tell your admin to create an account for you.")
|
||||
}
|
||||
|
||||
await authenticationService.signInWithPassword({ email: input.email, password: input.password })
|
||||
|
||||
return
|
||||
}
|
||||
)
|
||||
}
|
|
@ -16,7 +16,6 @@ export type TSignInSchema = z.infer<typeof SignInSchema>;
|
|||
export const SignInWithPasswordSchema = SignInSchema.pick({
|
||||
email: true,
|
||||
password: true,
|
||||
phone: true
|
||||
})
|
||||
|
||||
|
||||
|
@ -26,7 +25,6 @@ export type ISignInWithPasswordSchema = z.infer<typeof SignInWithPasswordSchema>
|
|||
export const defaulISignInWithPasswordSchemaValues: ISignInWithPasswordSchema = {
|
||||
email: "",
|
||||
password: "",
|
||||
phone: ""
|
||||
};
|
||||
|
||||
export const SignInPasswordlessSchema = SignInSchema.pick({
|
||||
|
@ -40,9 +38,13 @@ export const defaulISignInPasswordlessSchemaValues: ISignInPasswordlessSchema =
|
|||
email: "",
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Define the sign-in response schema using Zod
|
||||
export const SignInResponseSchema = z.object({
|
||||
success: z.boolean(),
|
||||
message: z.string(),
|
||||
redirectTo: z.string().optional(),
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ export class AuthenticationService implements IAuthenticationService {
|
|||
})
|
||||
}
|
||||
|
||||
async SignInWithPasswordSchema(credentials: ISignInWithPasswordSchema): Promise<void> {
|
||||
async signInWithPassword(credentials: ISignInWithPasswordSchema): Promise<void> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "SignInWithPasswordSchema Use Case",
|
||||
}, async () => {
|
||||
|
@ -79,7 +79,7 @@ export class AuthenticationService implements IAuthenticationService {
|
|||
})
|
||||
}
|
||||
|
||||
async SignUpWithEmailSchema(credentials: ISignUpWithEmailSchema): Promise<IUserSchema> {
|
||||
async SignUpWithEmail(credentials: ISignUpWithEmailSchema): Promise<IUserSchema> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "SignUpWithEmailSchema Use Case",
|
||||
}, async () => {
|
||||
|
@ -124,7 +124,7 @@ export class AuthenticationService implements IAuthenticationService {
|
|||
})
|
||||
}
|
||||
|
||||
async SignUpWithPhoneSchema(credentials: ISignUpWithPhoneSchema): Promise<IUserSchema> {
|
||||
async SignUpWithPhone(credentials: ISignUpWithPhoneSchema): Promise<IUserSchema> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from "zod";
|
||||
import { ISignInUseCase } from "@/src/application/use-cases/auth/sign-in.use-case";
|
||||
import { ISignInPasswordlessUseCase } from "@/src/application/use-cases/auth/sign-in-passwordless.use-case";
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
|
||||
|
@ -8,12 +8,12 @@ const signInInputSchema = z.object({
|
|||
email: z.string().min(1, "Email is Required").email("Please enter a valid email address"),
|
||||
})
|
||||
|
||||
export type ISignInController = ReturnType<typeof signInController>
|
||||
export type ISignInPasswordlessController = ReturnType<typeof signInPasswordlessController>
|
||||
|
||||
export const signInController =
|
||||
export const signInPasswordlessController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
signInUseCase: ISignInUseCase
|
||||
signInUseCase: ISignInPasswordlessUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof signInInputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "signIn Controller" }, async () => {
|
|
@ -0,0 +1,34 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { ISignInWithPasswordUseCase } from "@/src/application/use-cases/auth/sign-in-with-password.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
// Sign In Controller
|
||||
const signInWithPasswordInputSchema = z.object({
|
||||
email: z.string().min(1, "Email is Required").email("Please enter a valid email address"),
|
||||
password: z.string().min(1, "Password is Required")
|
||||
})
|
||||
|
||||
export type ISignInWithPasswordController = ReturnType<typeof signInWithPasswordController>
|
||||
|
||||
export const signInWithPasswordController = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
signInWithPasswordUseCase: ISignInWithPasswordUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof signInWithPasswordInputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "signInWithPassword Controller" },
|
||||
async () => {
|
||||
const { data, error: inputParseError } = signInWithPasswordInputSchema.safeParse(input)
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError(inputParseError.errors[0].message)
|
||||
}
|
||||
|
||||
return await signInWithPasswordUseCase({
|
||||
email: data.email,
|
||||
password: data.password
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue