refactor handler and queries
This commit is contained in:
parent
e84a6f52c0
commit
2faf6ce83e
|
@ -16,7 +16,7 @@ import {
|
|||
import { NavPreMain } from "./navigations/nav-pre-main";
|
||||
import { navData } from "@/prisma/data/nav";
|
||||
import { TeamSwitcher } from "../../../_components/team-switcher";
|
||||
import { useGetCurrentUserQuery } from "../dashboard/user-management/queries";
|
||||
import { useGetCurrentUserQuery } from "../dashboard/user-management/_queries/queries";
|
||||
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
|
|
|
@ -27,8 +27,8 @@ import { IconLogout, IconSettings, IconSparkles } from "@tabler/icons-react";
|
|||
import type { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
// import { signOut } from "@/app/(pages)/(auth)/action";
|
||||
import { SettingsDialog } from "../settings/setting-dialog";
|
||||
import { useSignOutHandler } from "@/app/(pages)/(auth)/handler";
|
||||
import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogCancel, AlertDialogAction } from "@/app/_components/ui/alert-dialog";
|
||||
import { useSignOutHandler } from "@/app/(pages)/(auth)/_handlers/use-sign-out";
|
||||
|
||||
export function NavUser({ user }: { user: IUserSchema | null }) {
|
||||
const { isMobile } = useSidebar();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/app/_components/ui/dialog"
|
||||
import { Button } from "@/app/_components/ui/button"
|
||||
import { Mail, Lock, Loader2 } from "lucide-react"
|
||||
import { useAddUserDialogHandler } from "../handler"
|
||||
import { ReactHookFormField } from "@/app/_components/react-hook-form-field"
|
||||
import { useAddUserDialogHandler } from "../_handlers/use-add-user-dialog"
|
||||
|
||||
interface AddUserDialogProps {
|
||||
open: boolean
|
||||
|
|
|
@ -16,10 +16,10 @@ import { Textarea } from "@/app/_components/ui/textarea";
|
|||
import { useMutation } from "@tanstack/react-query";
|
||||
import { inviteUser } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { toast } from "sonner";
|
||||
import { useInviteUserHandler } from "../handler";
|
||||
import { ReactHookFormField } from "@/app/_components/react-hook-form-field";
|
||||
import { Loader2, MailIcon } from "lucide-react";
|
||||
import { Separator } from "@/app/_components/ui/separator";
|
||||
import { useInviteUserHandler } from "../_handlers/use-invite-user";
|
||||
|
||||
|
||||
interface InviteUserDialogProps {
|
||||
|
|
|
@ -39,9 +39,9 @@ import {
|
|||
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { format } from "date-fns";
|
||||
import { sendMagicLink, sendPasswordRecovery } from "@/app/(pages)/(auth)/action";
|
||||
import { useUserDetailSheetHandlers } from "../handler";
|
||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { formatDate } from "@/app/_utils/common";
|
||||
import { useUserDetailSheetHandlers } from "../_handlers/use-detail-sheet";
|
||||
|
||||
interface UserDetailSheetProps {
|
||||
open: boolean;
|
||||
|
@ -56,104 +56,6 @@ export function UserDetailSheet({
|
|||
user,
|
||||
onUserUpdated,
|
||||
}: UserDetailSheetProps) {
|
||||
// const [isDeleting, setIsDeleting] = useState(false);
|
||||
// const [isLoading, setIsLoading] = useState({
|
||||
// deleteUser: false,
|
||||
// sendPasswordRecovery: false,
|
||||
// sendMagicLink: false,
|
||||
// toggleBan: false,
|
||||
// });
|
||||
|
||||
// const deleteUserMutation = useMutation({
|
||||
// mutationFn: () => deleteUser(user.id),
|
||||
// onMutate: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, deleteUser: true }));
|
||||
// setIsDeleting(true);
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// toast.success("User deleted successfully");
|
||||
// onUserUpdate();
|
||||
// onOpenChange(false);
|
||||
// },
|
||||
// onError: () => {
|
||||
// toast.error("Failed to delete user");
|
||||
// },
|
||||
// onSettled: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, deleteUser: false }));
|
||||
// setIsDeleting(false);
|
||||
// },
|
||||
// });
|
||||
|
||||
// const sendPasswordRecoveryMutation = useMutation({
|
||||
// mutationFn: () => {
|
||||
// if (!user.email) {
|
||||
// throw new Error("User does not have an email address");
|
||||
// }
|
||||
// return sendPasswordRecovery(user.email);
|
||||
// },
|
||||
// onMutate: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, sendPasswordRecovery: true }));
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// toast.success("Password recovery email sent");
|
||||
// },
|
||||
// onError: () => {
|
||||
// toast.error("Failed to send password recovery email");
|
||||
// },
|
||||
// onSettled: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, sendPasswordRecovery: false }));
|
||||
// },
|
||||
// });
|
||||
|
||||
// const sendMagicLinkMutation = useMutation({
|
||||
// mutationFn: () => {
|
||||
// if (!user.email) {
|
||||
// throw new Error("User does not have an email address");
|
||||
// }
|
||||
// return sendMagicLink(user.email);
|
||||
// },
|
||||
// onMutate: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, sendMagicLink: true }));
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// toast.success("Magic link sent successfully");
|
||||
// },
|
||||
// onError: () => {
|
||||
// toast.error("Failed to send magic link");
|
||||
// },
|
||||
// onSettled: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, sendMagicLink: false }));
|
||||
// },
|
||||
// });
|
||||
|
||||
// const toggleBanMutation = useMutation({
|
||||
// mutationFn: () => {
|
||||
// if (user.banned_until) {
|
||||
// return unbanUser(user.id);
|
||||
// } else {
|
||||
// const ban_duration = "7h"; // Example: Ban duration set to 7 days
|
||||
// return banUser({ id: user.id, ban_duration });
|
||||
// }
|
||||
// },
|
||||
// onMutate: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, toggleBan: true }));
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// toast.success("User ban status updated");
|
||||
// onUserUpdate();
|
||||
// },
|
||||
// onError: () => {
|
||||
// toast.error("Failed to update user ban status");
|
||||
// },
|
||||
// onSettled: () => {
|
||||
// setIsLoading((prev) => ({ ...prev, toggleBan: false }));
|
||||
// },
|
||||
// });
|
||||
|
||||
// const handleCopyItem = (item: string) => {
|
||||
// navigator.clipboard.writeText(item);
|
||||
// toast.success("Copied to clipboard");
|
||||
// };
|
||||
|
||||
const {
|
||||
handleDeleteUser,
|
||||
|
@ -364,7 +266,7 @@ export function UserDetailSheet({
|
|||
<Button
|
||||
variant={user.banned_until ? "outline" : "outline"}
|
||||
size="sm"
|
||||
onClick={handleToggleBan}
|
||||
onClick={() => handleToggleBan()}
|
||||
disabled={isBanPending || isUnbanPending}
|
||||
>
|
||||
{isBanPending || isUnbanPending ? (
|
||||
|
|
|
@ -18,7 +18,7 @@ import { useMutation } from "@tanstack/react-query"
|
|||
import { updateUser } from "../action"
|
||||
import { toast } from "sonner"
|
||||
import { UpdateUserSchema } from "@/src/entities/models/users/update-user.model"
|
||||
import { useUserProfileSheetHandlers } from "../handler"
|
||||
import { useUserProfileSheetHandlers } from "../_handlers/use-profile-sheet"
|
||||
|
||||
type UserProfileFormValues = z.infer<typeof UpdateUserSchema>
|
||||
|
||||
|
@ -34,7 +34,7 @@ export function UserProfileSheet({ open, onOpenChange, userData, onUserUpdated }
|
|||
const {
|
||||
form,
|
||||
handleUpdateUser,
|
||||
isUpdatePending,
|
||||
isPending,
|
||||
} = useUserProfileSheetHandlers({ open, userData, onOpenChange, onUserUpdated })
|
||||
|
||||
return (
|
||||
|
@ -214,14 +214,14 @@ export function UserProfileSheet({ open, onOpenChange, userData, onUserUpdated }
|
|||
type="button"
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => !isUpdatePending && onOpenChange(false)}
|
||||
disabled={isUpdatePending}
|
||||
onClick={() => !isPending && onOpenChange(false)}
|
||||
disabled={isPending}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button size="xs" type="submit" disabled={isUpdatePending}>
|
||||
{isUpdatePending && <Loader2 className="mr-1 h-4 w-4 animate-spin" />}
|
||||
{isUpdatePending ? "Saving..." : "Save"}
|
||||
<Button size="xs" type="submit" disabled={isPending}>
|
||||
{isPending && <Loader2 className="mr-1 h-4 w-4 animate-spin" />}
|
||||
{isPending ? "Saving..." : "Save"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -28,9 +28,9 @@ import { InviteUserDialog } from "./invite-user";
|
|||
import { AddUserDialog } from "./add-user-dialog";
|
||||
import { UserDetailSheet } from "./sheet";
|
||||
import { UserProfileSheet } from "./update-user";
|
||||
import { filterUsers, useUserManagementHandlers } from "../handler";
|
||||
import { createUserColumns } from "./users-table";
|
||||
import { useGetUsersQuery } from "../queries";
|
||||
import { useGetUsersQuery } from "../_queries/queries";
|
||||
import { filterUsers, useUserManagementHandlers } from "../_handlers/use-user-management";
|
||||
|
||||
export default function UserManagement() {
|
||||
|
||||
|
@ -61,7 +61,7 @@ export default function UserManagement() {
|
|||
handleUserUpdate,
|
||||
clearFilters,
|
||||
getActiveFilterCount,
|
||||
} = useUserManagementHandlers(refetch)
|
||||
} = useUserManagementHandlers()
|
||||
|
||||
// Apply filters to users
|
||||
const filteredUsers = useMemo(() => {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { Card, CardContent } from "@/app/_components/ui/card";
|
||||
import { Users, UserCheck, UserX } from "lucide-react";
|
||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { useGetUsersQuery } from "../queries";
|
||||
import { useGetUsersQuery } from "../_queries/queries";
|
||||
|
||||
|
||||
function calculateUserStats(users: IUserSchema[] | undefined) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Input } from "@/app/_components/ui/input"
|
|||
import { Avatar } from "@/app/_components/ui/avatar"
|
||||
import Image from "next/image"
|
||||
import { Badge } from "@/app/_components/ui/badge"
|
||||
import { useUserDetailSheetHandlers, useUsersHandlers } from "../handler"
|
||||
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations"
|
||||
|
||||
export type UserTableColumn = ColumnDef<IUserSchema, IUserSchema>
|
||||
|
||||
|
@ -26,11 +26,9 @@ export const createUserColumns = (
|
|||
handleUserUpdate: (user: IUserSchema) => void,
|
||||
): UserTableColumn[] => {
|
||||
|
||||
const {
|
||||
deleteUser,
|
||||
banUser,
|
||||
unbanUser,
|
||||
} = useUsersHandlers();
|
||||
const { mutateAsync: deleteUser } = useDeleteUserMutation();
|
||||
const { mutateAsync: banUser } = useBanUserMutation();
|
||||
const { mutateAsync: unbanUser } = useUnbanUserMutation();
|
||||
|
||||
return [
|
||||
{
|
||||
|
@ -329,9 +327,9 @@ export const createUserColumns = (
|
|||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
if (row.original.banned_until != null) {
|
||||
unbanUser(row.original.id)
|
||||
unbanUser({ id: row.original.id })
|
||||
} else {
|
||||
banUser(row.original.id)
|
||||
banUser({ id: row.original.id, ban_duration: "24h" })
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useCreateUserMutation } from "../_queries/mutations";
|
||||
import { CreateUserSchema, ICreateUserSchema } from "@/src/entities/models/users/create-user.model";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export const useAddUserDialogHandler = ({ onUserAdded, onOpenChange }: {
|
||||
onUserAdded: () => void;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) => {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { mutateAsync: createdUser, isPending } = useCreateUserMutation()
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors: errors },
|
||||
setError,
|
||||
getValues,
|
||||
clearErrors,
|
||||
watch,
|
||||
} = useForm<ICreateUserSchema>({
|
||||
resolver: zodResolver(CreateUserSchema),
|
||||
defaultValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
email_confirm: true,
|
||||
}
|
||||
});
|
||||
|
||||
const emailConfirm = watch("email_confirm");
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
|
||||
await createdUser(data, {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
|
||||
onUserAdded();
|
||||
onOpenChange(false);
|
||||
reset();
|
||||
},
|
||||
onError: (error) => {
|
||||
reset();
|
||||
toast.error(error.message);
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
reset();
|
||||
}
|
||||
onOpenChange(open);
|
||||
};
|
||||
|
||||
return {
|
||||
register,
|
||||
handleSubmit: onSubmit,
|
||||
reset,
|
||||
errors,
|
||||
isPending,
|
||||
getValues,
|
||||
clearErrors,
|
||||
emailConfirm,
|
||||
handleOpenChange,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { toast } from "sonner";
|
||||
import { useBanUserMutation, useDeleteUserMutation, useUnbanUserMutation } from "../_queries/mutations";
|
||||
import { useSendMagicLinkMutation, useSendPasswordRecoveryMutation } from "@/app/(pages)/(auth)/_queries/mutations";
|
||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration";
|
||||
import { handleCopyItem } from "@/app/_utils/common";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
export const useUserDetailSheetHandlers = ({ open, user, onUserUpdated, onOpenChange }: {
|
||||
open: boolean;
|
||||
user: IUserSchema;
|
||||
onUserUpdated: () => void;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) => {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { mutateAsync: deleteUser, isPending: isDeletePending } = useDeleteUserMutation();
|
||||
const { mutateAsync: sendPasswordRecovery, isPending: isSendPasswordRecoveryPending } = useSendPasswordRecoveryMutation();
|
||||
const { mutateAsync: sendMagicLink, isPending: isSendMagicLinkPending } = useSendMagicLinkMutation();
|
||||
const { mutateAsync: banUser, isPending: isBanPending } = useBanUserMutation();
|
||||
const { mutateAsync: unbanUser, isPending: isUnbanPending } = useUnbanUserMutation();
|
||||
|
||||
const handleDeleteUser = async () => {
|
||||
await deleteUser(user.id, {
|
||||
onSuccess: () => {
|
||||
onOpenChange(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleSendPasswordRecovery = async () => {
|
||||
if (!user.email) {
|
||||
toast.error("User has no email address");
|
||||
return;
|
||||
}
|
||||
await sendPasswordRecovery(user.email);
|
||||
};
|
||||
|
||||
const handleSendMagicLink = async () => {
|
||||
if (!user.email) {
|
||||
toast.error("User has no email address");
|
||||
return;
|
||||
}
|
||||
await sendMagicLink(user.email);
|
||||
};
|
||||
|
||||
const handleBanUser = async (ban_duration: ValidBanDuration = "24h") => {
|
||||
await banUser({ id: user.id, ban_duration: ban_duration }, {
|
||||
onSuccess: () => {
|
||||
onUserUpdated();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleUnbanUser = async () => {
|
||||
await unbanUser({ id: user.id }, {
|
||||
onSuccess: onUserUpdated
|
||||
});
|
||||
};
|
||||
|
||||
const handleToggleBan = async (ban_duration: ValidBanDuration = "24h") => {
|
||||
if (user.banned_until) {
|
||||
await unbanUser({ id: user.id }, {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
|
||||
toast(`${user.email} has been unbanned`);
|
||||
onUserUpdated();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await banUser({ id: user.id, ban_duration: ban_duration }, {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
|
||||
toast(`${user.email} has been banned`);
|
||||
onUserUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
handleDeleteUser,
|
||||
handleSendPasswordRecovery,
|
||||
handleSendMagicLink,
|
||||
handleBanUser,
|
||||
handleUnbanUser,
|
||||
handleToggleBan,
|
||||
handleCopyItem,
|
||||
isDeletePending,
|
||||
isSendPasswordRecoveryPending,
|
||||
isSendMagicLinkPending,
|
||||
isBanPending,
|
||||
isUnbanPending,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
import { defaulIInviteUserSchemaValues, IInviteUserSchema, InviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { useInviteUserMutation } from "../_queries/mutations";
|
||||
|
||||
export const useInviteUserHandler = ({ onUserInvited, onOpenChange }: {
|
||||
onUserInvited: () => void;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) => {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: inviteUser, isPending } = useInviteUserMutation();
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors: errors },
|
||||
setError,
|
||||
getValues,
|
||||
clearErrors,
|
||||
watch,
|
||||
} = useForm<IInviteUserSchema>({
|
||||
resolver: zodResolver(InviteUserSchema),
|
||||
defaultValues: defaulIInviteUserSchemaValues
|
||||
})
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
|
||||
const { email } = data;
|
||||
|
||||
await inviteUser(email, {
|
||||
onSuccess: () => {
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
|
||||
toast.success("Invitation sent");
|
||||
|
||||
onUserInvited();
|
||||
onOpenChange(false);
|
||||
reset();
|
||||
},
|
||||
onError: () => {
|
||||
reset();
|
||||
toast.error("Failed to send invitation");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
reset();
|
||||
}
|
||||
onOpenChange(open);
|
||||
};
|
||||
|
||||
return {
|
||||
register,
|
||||
handleSubmit: onSubmit,
|
||||
handleOpenChange,
|
||||
reset,
|
||||
getValues,
|
||||
clearErrors,
|
||||
watch,
|
||||
errors,
|
||||
isPending,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import { IUpdateUserSchema, UpdateUserSchema } from "@/src/entities/models/users/update-user.model";
|
||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useUpdateUserMutation } from "../_queries/mutations";
|
||||
|
||||
export const useUserProfileSheetHandlers = ({ open, onOpenChange, userData, onUserUpdated }: {
|
||||
open: boolean;
|
||||
userData: IUserSchema;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onUserUpdated: () => void;
|
||||
}) => {
|
||||
|
||||
const {
|
||||
mutateAsync: updateUser,
|
||||
isPending,
|
||||
} = useUpdateUserMutation()
|
||||
|
||||
// Initialize form with user data
|
||||
const form = useForm<IUpdateUserSchema>({
|
||||
resolver: zodResolver(UpdateUserSchema),
|
||||
defaultValues: {
|
||||
email: userData?.email || undefined,
|
||||
encrypted_password: userData?.encrypted_password || undefined,
|
||||
role: (userData?.role as "user" | "staff" | "admin") || "user",
|
||||
phone: userData?.phone || undefined,
|
||||
invited_at: userData?.invited_at || undefined,
|
||||
confirmed_at: userData?.confirmed_at || undefined,
|
||||
// recovery_sent_at: userData?.recovery_sent_at || undefined,
|
||||
last_sign_in_at: userData?.last_sign_in_at || undefined,
|
||||
created_at: userData?.created_at || undefined,
|
||||
updated_at: userData?.updated_at || undefined,
|
||||
is_anonymous: userData?.is_anonymous || false,
|
||||
profile: {
|
||||
// id: userData?.profile?.id || undefined,
|
||||
// user_id: userData?.profile?.user_id || undefined,
|
||||
avatar: userData?.profile?.avatar || undefined,
|
||||
username: userData?.profile?.username || undefined,
|
||||
first_name: userData?.profile?.first_name || undefined,
|
||||
last_name: userData?.profile?.last_name || undefined,
|
||||
bio: userData?.profile?.bio || undefined,
|
||||
address: userData?.profile?.address || {
|
||||
street: "",
|
||||
city: "",
|
||||
state: "",
|
||||
country: "",
|
||||
postal_code: "",
|
||||
},
|
||||
birth_date: userData?.profile?.birth_date ? new Date(userData.profile.birth_date) : undefined,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const handleUpdateUser = async () => {
|
||||
await updateUser({ id: userData.id, data: form.getValues() }, {
|
||||
onSuccess: () => {
|
||||
onUserUpdated();
|
||||
onOpenChange(false);
|
||||
},
|
||||
onError: () => {
|
||||
onOpenChange(false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
handleUpdateUser,
|
||||
form,
|
||||
isPending,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
import { IUserFilterOptionsSchema, IUserSchema } from "@/src/entities/models/users/users.model"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
export const useUserManagementHandlers = () => {
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [detailUser, setDetailUser] = useState<IUserSchema | null>(null)
|
||||
const [updateUser, setUpdateUser] = useState<IUserSchema | null>(null)
|
||||
const [isSheetOpen, setIsSheetOpen] = useState(false)
|
||||
const [isUpdateOpen, setIsUpdateOpen] = useState(false)
|
||||
const [isAddUserOpen, setIsAddUserOpen] = useState(false)
|
||||
const [isInviteUserOpen, setIsInviteUserOpen] = useState(false)
|
||||
|
||||
// Filter states
|
||||
const [filters, setFilters] = useState<IUserFilterOptionsSchema>({
|
||||
email: "",
|
||||
phone: "",
|
||||
lastSignIn: "",
|
||||
createdAt: "",
|
||||
status: [],
|
||||
})
|
||||
|
||||
// Handle opening the detail sheet
|
||||
const handleUserClick = (user: IUserSchema) => {
|
||||
setDetailUser(user)
|
||||
setIsSheetOpen(true)
|
||||
}
|
||||
|
||||
// Handle opening the update sheet
|
||||
const handleUserUpdate = (user: IUserSchema) => {
|
||||
setUpdateUser(user)
|
||||
setIsUpdateOpen(true)
|
||||
}
|
||||
|
||||
// Close detail sheet when update sheet opens
|
||||
useEffect(() => {
|
||||
if (isUpdateOpen) {
|
||||
setIsSheetOpen(false)
|
||||
}
|
||||
}, [isUpdateOpen])
|
||||
|
||||
// Reset detail user when sheet closes
|
||||
useEffect(() => {
|
||||
if (!isSheetOpen) {
|
||||
// Use a small delay to prevent flickering if another sheet is opening
|
||||
const timer = setTimeout(() => {
|
||||
if (!isSheetOpen && !isUpdateOpen) {
|
||||
setDetailUser(null)
|
||||
}
|
||||
}, 300)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [isSheetOpen, isUpdateOpen])
|
||||
|
||||
// Reset update user when update sheet closes
|
||||
useEffect(() => {
|
||||
if (!isUpdateOpen) {
|
||||
// Use a small delay to prevent flickering if another sheet is opening
|
||||
const timer = setTimeout(() => {
|
||||
if (!isUpdateOpen) {
|
||||
setUpdateUser(null)
|
||||
}
|
||||
}, 300)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [isUpdateOpen])
|
||||
|
||||
const clearFilters = () => {
|
||||
setFilters({
|
||||
email: "",
|
||||
phone: "",
|
||||
lastSignIn: "",
|
||||
createdAt: "",
|
||||
status: [],
|
||||
})
|
||||
}
|
||||
|
||||
const getActiveFilterCount = () => {
|
||||
return Object.values(filters).filter(
|
||||
(value) => (typeof value === "string" && value !== "") || (Array.isArray(value) && value.length > 0),
|
||||
).length
|
||||
}
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
detailUser,
|
||||
updateUser,
|
||||
isSheetOpen,
|
||||
setIsSheetOpen,
|
||||
isUpdateOpen,
|
||||
setIsUpdateOpen,
|
||||
isAddUserOpen,
|
||||
setIsAddUserOpen,
|
||||
isInviteUserOpen,
|
||||
setIsInviteUserOpen,
|
||||
filters,
|
||||
setFilters,
|
||||
handleUserClick,
|
||||
handleUserUpdate,
|
||||
clearFilters,
|
||||
getActiveFilterCount,
|
||||
}
|
||||
}
|
||||
|
||||
export const filterUsers = (users: IUserSchema[], searchQuery: string, filters: IUserFilterOptionsSchema): IUserSchema[] => {
|
||||
return users.filter((user) => {
|
||||
|
||||
// Global search
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase()
|
||||
const matchesSearch =
|
||||
user.email?.toLowerCase().includes(query) ||
|
||||
user.phone?.toLowerCase().includes(query) ||
|
||||
user.id.toLowerCase().includes(query)
|
||||
|
||||
if (!matchesSearch) return false
|
||||
}
|
||||
|
||||
// Email filter
|
||||
if (filters.email && !user.email?.toLowerCase().includes(filters.email.toLowerCase())) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Phone filter
|
||||
if (filters.phone && !user.phone?.toLowerCase().includes(filters.phone.toLowerCase())) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Last sign in filter
|
||||
if (filters.lastSignIn) {
|
||||
if (filters.lastSignIn === "never" && user.last_sign_in_at) {
|
||||
return false
|
||||
} else if (filters.lastSignIn === "today") {
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null
|
||||
if (!signInDate || signInDate < today) return false
|
||||
} else if (filters.lastSignIn === "week") {
|
||||
const weekAgo = new Date()
|
||||
weekAgo.setDate(weekAgo.getDate() - 7)
|
||||
const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null
|
||||
if (!signInDate || signInDate < weekAgo) return false
|
||||
} else if (filters.lastSignIn === "month") {
|
||||
const monthAgo = new Date()
|
||||
monthAgo.setMonth(monthAgo.getMonth() - 1)
|
||||
const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null
|
||||
if (!signInDate || signInDate < monthAgo) return false
|
||||
}
|
||||
}
|
||||
|
||||
// Created at filter
|
||||
if (filters.createdAt) {
|
||||
if (filters.createdAt === "today") {
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
const createdAt = user.created_at ? (user.created_at ? new Date(user.created_at) : new Date()) : new Date()
|
||||
if (createdAt < today) return false
|
||||
} else if (filters.createdAt === "week") {
|
||||
const weekAgo = new Date()
|
||||
weekAgo.setDate(weekAgo.getDate() - 7)
|
||||
const createdAt = user.created_at ? new Date(user.created_at) : new Date()
|
||||
if (createdAt < weekAgo) return false
|
||||
} else if (filters.createdAt === "month") {
|
||||
const monthAgo = new Date()
|
||||
monthAgo.setMonth(monthAgo.getMonth() - 1)
|
||||
const createdAt = user.created_at ? new Date(user.created_at) : new Date()
|
||||
if (createdAt < monthAgo) return false
|
||||
}
|
||||
}
|
||||
|
||||
// Status filter
|
||||
if (filters.status.length > 0) {
|
||||
const userStatus = user.banned_until ? "banned" : !user.email_confirmed_at ? "unconfirmed" : "active"
|
||||
|
||||
if (!filters.status.includes(userStatus)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import { ICreateUserSchema } from "@/src/entities/models/users/create-user.model";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { banUser, createUser, deleteUser, inviteUser, unbanUser, updateUser } from "../action";
|
||||
import { IUpdateUserSchema } from "@/src/entities/models/users/update-user.model";
|
||||
import { ICredentialsInviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
||||
import { IBanUserSchema, ICredentialsBanUserSchema } from "@/src/entities/models/users/ban-user.model";
|
||||
import { ICredentialsUnbanUserSchema } from "@/src/entities/models/users/unban-user.model";
|
||||
import { ValidBanDuration } from "@/app/_lib/types/ban-duration";
|
||||
|
||||
export const useCreateUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "create"],
|
||||
mutationFn: (data: ICreateUserSchema) => createUser(data),
|
||||
})
|
||||
}
|
||||
|
||||
export const useUpdateUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "update"],
|
||||
mutationFn: (args: { id: string; data: IUpdateUserSchema }) => updateUser(args.id, args.data)
|
||||
})
|
||||
}
|
||||
|
||||
export const useDeleteUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "delete"],
|
||||
mutationFn: (id: string) => deleteUser(id),
|
||||
})
|
||||
}
|
||||
|
||||
export const useInviteUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "invite"],
|
||||
mutationFn: (email: string) => inviteUser({ email }),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const useBanUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "ban"],
|
||||
mutationFn: (args: { id: string; ban_duration: ValidBanDuration }) => banUser({ id: args.id }, { ban_duration: args.ban_duration }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useUnbanUserMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["user", "unban"],
|
||||
mutationFn: (credential: ICredentialsUnbanUserSchema) => unbanUser(credential),
|
||||
})
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getCurrentUser, getUserByEmail, getUserById, getUserByUsername, getUsers } from "../action";
|
||||
|
||||
export const useGetUsersQuery = () => {
|
||||
return useQuery<IUserSchema[]>({
|
||||
queryKey: ["users"],
|
||||
queryFn: () => getUsers()
|
||||
});
|
||||
}
|
||||
|
||||
export const useGetUserByEmailQuery = (email: string) => {
|
||||
return useQuery<IUserSchema>({
|
||||
queryKey: ["user", "email", email],
|
||||
queryFn: () => getUserByEmail({ email }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useGetUserByIdQuery = (id: string) => {
|
||||
return useQuery<IUserSchema>({
|
||||
queryKey: ["user", "id", id],
|
||||
queryFn: () => getUserById({ id }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useGetUserByUsernameQuery = (username: string) => {
|
||||
return useQuery<IUserSchema>({
|
||||
queryKey: ["user", "username", username],
|
||||
queryFn: () => getUserByUsername({ username }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useGetCurrentUserQuery = () => {
|
||||
return useQuery<IUserSchema>({
|
||||
queryKey: ["user", "current"],
|
||||
queryFn: () => getCurrentUser(),
|
||||
})
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,212 +1,212 @@
|
|||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
banUser,
|
||||
getCurrentUser,
|
||||
getUserByEmail,
|
||||
getUserById,
|
||||
getUsers,
|
||||
unbanUser,
|
||||
inviteUser,
|
||||
createUser,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
getUserByUsername
|
||||
} from "./action";
|
||||
import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { IBanDuration, IBanUserSchema, ICredentialsBanUserSchema } from "@/src/entities/models/users/ban-user.model";
|
||||
import { ICredentialsUnbanUserSchema, IUnbanUserSchema } from "@/src/entities/models/users/unban-user.model";
|
||||
import { ICreateUserSchema } from "@/src/entities/models/users/create-user.model";
|
||||
import { IUpdateUserSchema } from "@/src/entities/models/users/update-user.model";
|
||||
import { ICredentialsInviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
||||
import { ICredentialGetUserByEmailSchema, ICredentialGetUserByIdSchema, ICredentialGetUserByUsernameSchema, IGetUserByEmailSchema, IGetUserByIdSchema, IGetUserByUsernameSchema } from "@/src/entities/models/users/read-user.model";
|
||||
// import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
// import {
|
||||
// banUser,
|
||||
// getCurrentUser,
|
||||
// getUserByEmail,
|
||||
// getUserById,
|
||||
// getUsers,
|
||||
// unbanUser,
|
||||
// inviteUser,
|
||||
// createUser,
|
||||
// updateUser,
|
||||
// deleteUser,
|
||||
// getUserByUsername
|
||||
// } from "./action";
|
||||
// import { IUserSchema } from "@/src/entities/models/users/users.model";
|
||||
// import { IBanDuration, IBanUserSchema, ICredentialsBanUserSchema } from "@/src/entities/models/users/ban-user.model";
|
||||
// import { ICredentialsUnbanUserSchema, IUnbanUserSchema } from "@/src/entities/models/users/unban-user.model";
|
||||
// import { ICreateUserSchema } from "@/src/entities/models/users/create-user.model";
|
||||
// import { IUpdateUserSchema } from "@/src/entities/models/users/update-user.model";
|
||||
// import { ICredentialsInviteUserSchema } from "@/src/entities/models/users/invite-user.model";
|
||||
// import { ICredentialGetUserByEmailSchema, ICredentialGetUserByIdSchema, ICredentialGetUserByUsernameSchema, IGetUserByEmailSchema, IGetUserByIdSchema, IGetUserByUsernameSchema } from "@/src/entities/models/users/read-user.model";
|
||||
|
||||
const useUsersAction = () => {
|
||||
// const useUsersAction = () => {
|
||||
|
||||
// For all users (no parameters needed)
|
||||
const getUsersQuery = useQuery<IUserSchema[]>({
|
||||
queryKey: ["users"],
|
||||
queryFn: async () => await getUsers()
|
||||
});
|
||||
// // For all users (no parameters needed)
|
||||
// const getUsersQuery = useQuery<IUserSchema[]>({
|
||||
// queryKey: ["users"],
|
||||
// queryFn: () => getUsers()
|
||||
// });
|
||||
|
||||
// Current user query doesn't need parameters
|
||||
const getCurrentUserQuery = useQuery<IUserSchema>({
|
||||
queryKey: ["user", "current"],
|
||||
queryFn: async () => await getCurrentUser()
|
||||
});
|
||||
// // Current user query doesn't need parameters
|
||||
// const getCurrentUserQuery = useQuery<IUserSchema>({
|
||||
// queryKey: ["user", "current"],
|
||||
// queryFn: () => getCurrentUser()
|
||||
// });
|
||||
|
||||
const getUserByIdQuery = (credential: ICredentialGetUserByIdSchema) => useQuery<IUserSchema>({
|
||||
queryKey: ["user", "id", credential.id],
|
||||
queryFn: async () => await getUserById(credential)
|
||||
});
|
||||
// const getUserByIdQuery = (credential: ICredentialGetUserByIdSchema) => useQuery<IUserSchema>({
|
||||
// queryKey: ["user", "id", credential.id],
|
||||
// queryFn: () => getUserById(credential)
|
||||
// });
|
||||
|
||||
const getUserByEmailQuery = (credential: IGetUserByEmailSchema) => useQuery<IUserSchema>({
|
||||
queryKey: ["user", "email", credential.email],
|
||||
queryFn: async () => await getUserByEmail(credential)
|
||||
});
|
||||
// const getUserByEmailQuery = (credential: IGetUserByEmailSchema) => useQuery<IUserSchema>({
|
||||
// queryKey: ["user", "email", credential.email],
|
||||
// queryFn: () => getUserByEmail(credential)
|
||||
// });
|
||||
|
||||
const getUserByUsernameQuery = (credential: IGetUserByUsernameSchema) => useQuery<IUserSchema>({
|
||||
queryKey: ["user", "username", credential.username],
|
||||
queryFn: async () => await getUserByUsername(credential)
|
||||
});
|
||||
// const getUserByUsernameQuery = (credential: IGetUserByUsernameSchema) => useQuery<IUserSchema>({
|
||||
// queryKey: ["user", "username", credential.username],
|
||||
// queryFn: () => getUserByUsername(credential)
|
||||
// });
|
||||
|
||||
// Mutations that don't need dynamic parameters
|
||||
const banUserMutation = useMutation({
|
||||
mutationKey: ["banUser"],
|
||||
mutationFn: async ({ credential, data }: { credential: ICredentialsBanUserSchema; data: IBanUserSchema }) => await banUser(credential, data)
|
||||
});
|
||||
// // Mutations that don't need dynamic parameters
|
||||
// const banUserMutation = (credential: ICredentialsBanUserSchema, data: IBanUserSchema) => useMutation({
|
||||
// mutationKey: ["banUser"],
|
||||
// mutationFn: () => banUser(credential, data)
|
||||
// });
|
||||
|
||||
const unbanUserMutation = useMutation({
|
||||
mutationKey: ["unbanUser"],
|
||||
mutationFn: async (credential: ICredentialsUnbanUserSchema) => await unbanUser(credential)
|
||||
});
|
||||
// const unbanUserMutation = useMutation({
|
||||
// mutationKey: ["unbanUser"],
|
||||
// mutationFn: async (credential: ICredentialsUnbanUserSchema) => await unbanUser(credential)
|
||||
// });
|
||||
|
||||
// Create functions that return configured hooks
|
||||
const inviteUserMutation = useMutation({
|
||||
mutationKey: ["inviteUser"],
|
||||
mutationFn: async (credential: ICredentialsInviteUserSchema) => await inviteUser(credential)
|
||||
});
|
||||
// // Create functions that return configured hooks
|
||||
// const inviteUserMutation = useMutation({
|
||||
// mutationKey: ["inviteUser"],
|
||||
// mutationFn: async (credential: ICredentialsInviteUserSchema) => await inviteUser(credential)
|
||||
// });
|
||||
|
||||
const createUserMutation = useMutation({
|
||||
mutationKey: ["createUser"],
|
||||
mutationFn: async (data: ICreateUserSchema) => await createUser(data)
|
||||
});
|
||||
// const createUserMutation = useMutation({
|
||||
// mutationKey: ["createUser"],
|
||||
// mutationFn: async (data: ICreateUserSchema) => await createUser(data)
|
||||
// });
|
||||
|
||||
const updateUserMutation = useMutation({
|
||||
mutationKey: ["updateUser"],
|
||||
mutationFn: async (params: { id: string; data: IUpdateUserSchema }) => updateUser(params.id, params.data)
|
||||
});
|
||||
// const updateUserMutation = useMutation({
|
||||
// mutationKey: ["updateUser"],
|
||||
// mutationFn: async (params: { id: string; data: IUpdateUserSchema }) => updateUser(params.id, params.data)
|
||||
// });
|
||||
|
||||
const deleteUserMutation = useMutation({
|
||||
mutationKey: ["deleteUser"],
|
||||
mutationFn: async (id: string) => await deleteUser(id)
|
||||
});
|
||||
// const deleteUserMutation = useMutation({
|
||||
// mutationKey: ["deleteUser"],
|
||||
// mutationFn: async (id: string) => await deleteUser(id)
|
||||
// });
|
||||
|
||||
return {
|
||||
getUsers: getUsersQuery,
|
||||
getCurrentUser: getCurrentUserQuery,
|
||||
getUserById: getUserByIdQuery,
|
||||
getUserByEmailQuery,
|
||||
getUserByUsernameQuery,
|
||||
banUser: banUserMutation,
|
||||
unbanUser: unbanUserMutation,
|
||||
inviteUser: inviteUserMutation,
|
||||
createUser: createUserMutation,
|
||||
updateUser: updateUserMutation,
|
||||
deleteUser: deleteUserMutation
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// getUsers: getUsersQuery,
|
||||
// getCurrentUser: getCurrentUserQuery,
|
||||
// getUserById: getUserByIdQuery,
|
||||
// getUserByEmailQuery,
|
||||
// getUserByUsernameQuery,
|
||||
// banUser: banUserMutation,
|
||||
// unbanUser: unbanUserMutation,
|
||||
// inviteUser: inviteUserMutation,
|
||||
// createUser: createUserMutation,
|
||||
// updateUser: updateUserMutation,
|
||||
// deleteUser: deleteUserMutation
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useGetUsersQuery = () => {
|
||||
const { getUsers } = useUsersAction();
|
||||
// export const useGetUsersQuery = () => {
|
||||
// const { getUsers } = useUsersAction();
|
||||
|
||||
return {
|
||||
data: getUsers.data,
|
||||
isPending: getUsers.isPending,
|
||||
error: getUsers.error,
|
||||
refetch: getUsers.refetch,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// data: getUsers.data,
|
||||
// isPending: getUsers.isPending,
|
||||
// error: getUsers.error,
|
||||
// refetch: getUsers.refetch,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useGetCurrentUserQuery = () => {
|
||||
const { getCurrentUser } = useUsersAction();
|
||||
// export const useGetCurrentUserQuery = () => {
|
||||
// const { getCurrentUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
data: getCurrentUser.data,
|
||||
isPending: getCurrentUser.isPending,
|
||||
error: getCurrentUser.error,
|
||||
refetch: getCurrentUser.refetch,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// data: getCurrentUser.data,
|
||||
// isPending: getCurrentUser.isPending,
|
||||
// error: getCurrentUser.error,
|
||||
// refetch: getCurrentUser.refetch,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useGetUserByIdQuery = (credential: ICredentialGetUserByIdSchema) => {
|
||||
const { getUserById } = useUsersAction();
|
||||
// export const useGetUserByIdQuery = (credential: ICredentialGetUserByIdSchema) => {
|
||||
// const { getUserById } = useUsersAction();
|
||||
|
||||
return {
|
||||
data: getUserById(credential).data,
|
||||
isPending: getUserById(credential).isPending,
|
||||
error: getUserById(credential).error,
|
||||
refetch: getUserById(credential).refetch,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// data: getUserById(credential).data,
|
||||
// isPending: getUserById(credential).isPending,
|
||||
// error: getUserById(credential).error,
|
||||
// refetch: getUserById(credential).refetch,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useGetUserByEmailQuery = (credential: ICredentialGetUserByEmailSchema) => {
|
||||
const { getUserByEmailQuery } = useUsersAction();
|
||||
// export const useGetUserByEmailQuery = (credential: ICredentialGetUserByEmailSchema) => {
|
||||
// const { getUserByEmailQuery } = useUsersAction();
|
||||
|
||||
return {
|
||||
data: getUserByEmailQuery(credential).data,
|
||||
isPending: getUserByEmailQuery(credential).isPending,
|
||||
error: getUserByEmailQuery(credential).error,
|
||||
refetch: getUserByEmailQuery(credential).refetch,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// data: getUserByEmailQuery(credential).data,
|
||||
// isPending: getUserByEmailQuery(credential).isPending,
|
||||
// error: getUserByEmailQuery(credential).error,
|
||||
// refetch: getUserByEmailQuery(credential).refetch,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useGetUserByUsernameQuery = (credential: ICredentialGetUserByUsernameSchema) => {
|
||||
const { getUserByUsernameQuery } = useUsersAction();
|
||||
// export const useGetUserByUsernameQuery = (credential: ICredentialGetUserByUsernameSchema) => {
|
||||
// const { getUserByUsernameQuery } = useUsersAction();
|
||||
|
||||
return {
|
||||
data: getUserByUsernameQuery(credential).data,
|
||||
isPending: getUserByUsernameQuery(credential).isPending,
|
||||
error: getUserByUsernameQuery(credential).error,
|
||||
refetch: getUserByUsernameQuery(credential).refetch,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// data: getUserByUsernameQuery(credential).data,
|
||||
// isPending: getUserByUsernameQuery(credential).isPending,
|
||||
// error: getUserByUsernameQuery(credential).error,
|
||||
// refetch: getUserByUsernameQuery(credential).refetch,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useCreateUserMutation = () => {
|
||||
const { createUser } = useUsersAction();
|
||||
// export const useCreateUserMutation = () => {
|
||||
// const { createUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
createUser: createUser.mutateAsync,
|
||||
isPending: createUser.isPending,
|
||||
errors: createUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// createUser: createUser.mutateAsync,
|
||||
// isPending: createUser.isPending,
|
||||
// errors: createUser.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useInviteUserMutation = () => {
|
||||
const { inviteUser } = useUsersAction();
|
||||
// export const useInviteUserMutation = () => {
|
||||
// const { inviteUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
inviteUser: inviteUser.mutateAsync,
|
||||
isPending: inviteUser.isPending,
|
||||
errors: inviteUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// inviteUser: inviteUser.mutateAsync,
|
||||
// isPending: inviteUser.isPending,
|
||||
// errors: inviteUser.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useUpdateUserMutation = () => {
|
||||
const { updateUser } = useUsersAction();
|
||||
// export const useUpdateUserMutation = () => {
|
||||
// const { updateUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
updateUser: updateUser.mutateAsync,
|
||||
isPending: updateUser.isPending,
|
||||
errors: updateUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// updateUser: updateUser.mutateAsync,
|
||||
// isPending: updateUser.isPending,
|
||||
// errors: updateUser.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useBanUserMutation = () => {
|
||||
const { banUser } = useUsersAction();
|
||||
// export const useBanUserMutation = () => {
|
||||
// const { banUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
banUser: banUser.mutateAsync,
|
||||
isPending: banUser.isPending,
|
||||
errors: banUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// banUser: banUser.mutateAsync,
|
||||
// isPending: banUser.isPending,
|
||||
// errors: banUser.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useUnbanUserMutation = () => {
|
||||
const { unbanUser } = useUsersAction();
|
||||
// export const useUnbanUserMutation = () => {
|
||||
// const { unbanUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
unbanUser: unbanUser.mutateAsync,
|
||||
isPending: unbanUser.isPending,
|
||||
errors: unbanUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// unbanUser: unbanUser.mutateAsync,
|
||||
// isPending: unbanUser.isPending,
|
||||
// errors: unbanUser.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useDeleteUserMutation = () => {
|
||||
const { deleteUser } = useUsersAction();
|
||||
// export const useDeleteUserMutation = () => {
|
||||
// const { deleteUser } = useUsersAction();
|
||||
|
||||
return {
|
||||
deleteUser: deleteUser.mutateAsync,
|
||||
isPending: deleteUser.isPending,
|
||||
errors: deleteUser.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// deleteUser: deleteUser.mutateAsync,
|
||||
// isPending: deleteUser.isPending,
|
||||
// errors: deleteUser.error,
|
||||
// }
|
||||
// }
|
|
@ -10,7 +10,7 @@ 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 "../handler";
|
||||
import { useSignInHandler } from "../_handlers/use-sign-in";
|
||||
|
||||
export function SignInForm({
|
||||
className,
|
||||
|
@ -33,7 +33,7 @@ export function SignInForm({
|
|||
// setLoading(false);
|
||||
// };
|
||||
|
||||
const { isPending, handleSignIn, error, errors, clearError } = useSignInHandler();
|
||||
const { register, isPending, handleSignIn, error, errors } = useSignInHandler();
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -81,9 +81,7 @@ export function SignInForm({
|
|||
label="Email"
|
||||
input={
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
{...register("email")}
|
||||
placeholder="you@example.com"
|
||||
className={`bg-[#1C1C1C] border-gray-800`}
|
||||
error={!!errors}
|
||||
|
|
|
@ -16,8 +16,8 @@ import {
|
|||
import { cn } from "@/app/_lib/utils";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { useVerifyOtpHandler } from "../handler";
|
||||
import { Button } from "@/app/_components/ui/button";
|
||||
import { useVerifyOtpHandler } from "../_handlers/use-verify-otp";
|
||||
|
||||
interface VerifyOtpFormProps extends React.HTMLAttributes<HTMLDivElement> {}
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { useSignInMutation } from "../_queries/mutations";
|
||||
import { toast } from "sonner";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { ISignInPasswordlessSchema, SignInPasswordlessSchema } from "@/src/entities/models/auth/sign-in.model";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
export function useSignInHandler() {
|
||||
const { mutateAsync: signIn, isPending, error: errors } = useSignInMutation();
|
||||
const { router } = useNavigations();
|
||||
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const {
|
||||
register,
|
||||
reset,
|
||||
formState: { errors: formErrors },
|
||||
setError: setFormError,
|
||||
} = useForm<ISignInPasswordlessSchema>({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
},
|
||||
resolver: zodResolver(SignInPasswordlessSchema),
|
||||
})
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
if (isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
|
||||
const formData = new FormData(event.currentTarget);
|
||||
const email = formData.get('email')?.toString();
|
||||
|
||||
const res = await signIn(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);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// const onSubmit = handleSubmit(async (data) => {
|
||||
// if (isPending) return;
|
||||
|
||||
// console.log(data);
|
||||
|
||||
// setError(undefined);
|
||||
|
||||
// const { email } = data;
|
||||
|
||||
// const formData = new FormData();
|
||||
// formData.append('email', email);
|
||||
|
||||
// const res = await signIn(formData);
|
||||
|
||||
// if (!res?.error) {
|
||||
// toast('An email has been sent to you. Please check your inbox.');
|
||||
// router.push(`/verify-otp?email=${encodeURIComponent(email)}`);
|
||||
// } else {
|
||||
// setError(res.error);
|
||||
// }
|
||||
// })
|
||||
|
||||
return {
|
||||
// formData,
|
||||
// handleChange,
|
||||
reset,
|
||||
register,
|
||||
handleSignIn: handleSubmit,
|
||||
error,
|
||||
isPending,
|
||||
errors: !!error || errors,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { useState } from "react";
|
||||
import { useSignOutMutation } from "../_queries/mutations";
|
||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { toast } from "sonner";
|
||||
import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||
|
||||
export function useSignOutHandler() {
|
||||
const { mutateAsync: signOut, isPending, error: errors } = useSignOutMutation();
|
||||
const { router } = useNavigations();
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const handleSignOut = async () => {
|
||||
if (isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
|
||||
await signOut(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: isPending,
|
||||
errors: !!error || errors,
|
||||
clearError: () => setError(undefined),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { IVerifyOtpSchema, verifyOtpSchema } from "@/src/entities/models/auth/verify-otp.model";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { useVerifyOtpMutation } from "../_queries/mutations";
|
||||
|
||||
export function useVerifyOtpHandler(email: string) {
|
||||
const { mutateAsync: verifyOtp, isPending } = useVerifyOtpMutation();
|
||||
const { router } = useNavigations();
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit: hookFormSubmit,
|
||||
control,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset
|
||||
} = 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 (isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
|
||||
// Create FormData object
|
||||
const formData = new FormData();
|
||||
formData.append('email', data.email);
|
||||
formData.append('token', data.token);
|
||||
|
||||
await verifyOtp(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: isPending,
|
||||
clearError: () => setError(undefined),
|
||||
reset,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { useMutation } from "@tanstack/react-query"
|
||||
import { sendMagicLink, sendPasswordRecovery, signIn, signOut, verifyOtp } from "../action"
|
||||
|
||||
export const useSignInMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["signIn"],
|
||||
mutationFn: async (formData: FormData) => await signIn(formData),
|
||||
})
|
||||
}
|
||||
|
||||
export const useSignOutMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["signOut"],
|
||||
mutationFn: async () => await signOut(),
|
||||
})
|
||||
}
|
||||
|
||||
export const useSendMagicLinkMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["sendMagicLink"],
|
||||
mutationFn: async (email: string) => await sendMagicLink(email),
|
||||
})
|
||||
}
|
||||
|
||||
export const useSendPasswordRecoveryMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["sendPasswordRecovery"],
|
||||
mutationFn: async (email: string) => await sendPasswordRecovery(email),
|
||||
})
|
||||
}
|
||||
|
||||
export const useVerifyOtpMutation = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["verifyOtp"],
|
||||
mutationFn: async (formData: FormData) => await verifyOtp(formData),
|
||||
})
|
||||
}
|
|
@ -1,161 +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';
|
||||
// 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();
|
||||
// /**
|
||||
// * 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 [error, setError] = useState<string>();
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
if (signIn.isPending) return;
|
||||
// const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
// event.preventDefault();
|
||||
// if (signIn.isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
// setError(undefined);
|
||||
|
||||
const formData = new FormData(event.currentTarget);
|
||||
const email = formData.get('email')?.toString();
|
||||
// const formData = new FormData(event.currentTarget);
|
||||
// const email = formData.get('email')?.toString();
|
||||
|
||||
const res = await signIn.mutateAsync(formData);
|
||||
// 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);
|
||||
}
|
||||
// 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),
|
||||
};
|
||||
}
|
||||
// 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>();
|
||||
// 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 {
|
||||
// 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);
|
||||
// const handleOtpChange = (
|
||||
// value: string,
|
||||
// onChange: (value: string) => void
|
||||
// ) => {
|
||||
// onChange(value);
|
||||
|
||||
if (value.length === 6) {
|
||||
handleSubmit();
|
||||
}
|
||||
// if (value.length === 6) {
|
||||
// handleSubmit();
|
||||
// }
|
||||
|
||||
// Clear error when user starts typing
|
||||
if (error) {
|
||||
setError(undefined);
|
||||
}
|
||||
};
|
||||
// // Clear error when user starts typing
|
||||
// if (error) {
|
||||
// setError(undefined);
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleSubmit = hookFormSubmit(async (data) => {
|
||||
if (verifyOtp.isPending) return;
|
||||
// const handleSubmit = hookFormSubmit(async (data) => {
|
||||
// if (verifyOtp.isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
// setError(undefined);
|
||||
|
||||
// Create FormData object
|
||||
const formData = new FormData();
|
||||
formData.append('email', data.email);
|
||||
formData.append('token', data.token);
|
||||
// // 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);
|
||||
},
|
||||
});
|
||||
});
|
||||
// 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),
|
||||
};
|
||||
}
|
||||
// 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>();
|
||||
// export function useSignOutHandler() {
|
||||
// const { signOut } = useAuthActions();
|
||||
// const { router } = useNavigations();
|
||||
// const [error, setError] = useState<string>();
|
||||
|
||||
const handleSignOut = async () => {
|
||||
if (signOut.isPending) return;
|
||||
// const handleSignOut = async () => {
|
||||
// if (signOut.isPending) return;
|
||||
|
||||
setError(undefined);
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
// 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),
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// handleSignOut,
|
||||
// error,
|
||||
// isPending: signOut.isPending,
|
||||
// errors: !!error || signOut.error,
|
||||
// clearError: () => setError(undefined),
|
||||
// };
|
||||
// }
|
||||
|
|
|
@ -1,89 +1,89 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import { sendMagicLink, sendPasswordRecovery, signIn, signOut, verifyOtp } from './action';
|
||||
// import { useMutation } from '@tanstack/react-query';
|
||||
// import { sendMagicLink, sendPasswordRecovery, signIn, signOut, verifyOtp } from './action';
|
||||
|
||||
export function useAuthActions() {
|
||||
// Sign In Mutation
|
||||
const signInMutation = useMutation({
|
||||
mutationKey: ["signIn"],
|
||||
mutationFn: async (formData: FormData) => await signIn(formData)
|
||||
});
|
||||
// export function useAuthActions() {
|
||||
// // Sign In Mutation
|
||||
// const signInMutation = useMutation({
|
||||
// mutationKey: ["signIn"],
|
||||
// mutationFn: async (formData: FormData) => await signIn(formData)
|
||||
// });
|
||||
|
||||
// Verify OTP Mutation
|
||||
const verifyOtpMutation = useMutation({
|
||||
mutationKey: ["verifyOtp"],
|
||||
mutationFn: async (formData: FormData) => await verifyOtp(formData)
|
||||
});
|
||||
// // Verify OTP Mutation
|
||||
// const verifyOtpMutation = useMutation({
|
||||
// mutationKey: ["verifyOtp"],
|
||||
// mutationFn: async (formData: FormData) => await verifyOtp(formData)
|
||||
// });
|
||||
|
||||
const signOutMutation = useMutation({
|
||||
mutationKey: ["signOut"],
|
||||
mutationFn: async () => await signOut()
|
||||
});
|
||||
// const signOutMutation = useMutation({
|
||||
// mutationKey: ["signOut"],
|
||||
// mutationFn: async () => await signOut()
|
||||
// });
|
||||
|
||||
const sendMagicLinkMutation = useMutation({
|
||||
mutationKey: ["sendMagicLink"],
|
||||
mutationFn: async (email: string) => await sendMagicLink(email)
|
||||
});
|
||||
// const sendMagicLinkMutation = useMutation({
|
||||
// mutationKey: ["sendMagicLink"],
|
||||
// mutationFn: async (email: string) => await sendMagicLink(email)
|
||||
// });
|
||||
|
||||
const sendPasswordRecoveryMutation = useMutation({
|
||||
mutationKey: ["sendPasswordRecovery"],
|
||||
mutationFn: async (email: string) => await sendPasswordRecovery(email)
|
||||
});
|
||||
// const sendPasswordRecoveryMutation = useMutation({
|
||||
// mutationKey: ["sendPasswordRecovery"],
|
||||
// mutationFn: async (email: string) => await sendPasswordRecovery(email)
|
||||
// });
|
||||
|
||||
return {
|
||||
signIn: signInMutation,
|
||||
verifyOtp: verifyOtpMutation,
|
||||
signOut: signOutMutation,
|
||||
sendMagicLink: sendMagicLinkMutation,
|
||||
sendPasswordRecovery: sendPasswordRecoveryMutation
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// signIn: signInMutation,
|
||||
// verifyOtp: verifyOtpMutation,
|
||||
// signOut: signOutMutation,
|
||||
// sendMagicLink: sendMagicLinkMutation,
|
||||
// sendPasswordRecovery: sendPasswordRecoveryMutation
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useSignInMutation = () => {
|
||||
const { signIn } = useAuthActions();
|
||||
// export const useSignInMutation = () => {
|
||||
// const { signIn } = useAuthActions();
|
||||
|
||||
return {
|
||||
signIn: signIn.mutateAsync,
|
||||
isPending: signIn.isPending,
|
||||
error: signIn.error,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// signIn: signIn.mutateAsync,
|
||||
// isPending: signIn.isPending,
|
||||
// error: signIn.error,
|
||||
// };
|
||||
// }
|
||||
|
||||
export const useVerifyOtpMutation = () => {
|
||||
const { verifyOtp } = useAuthActions();
|
||||
// export const useVerifyOtpMutation = () => {
|
||||
// const { verifyOtp } = useAuthActions();
|
||||
|
||||
return {
|
||||
verifyOtp: verifyOtp.mutateAsync,
|
||||
isPending: verifyOtp.isPending,
|
||||
error: verifyOtp.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// verifyOtp: verifyOtp.mutateAsync,
|
||||
// isPending: verifyOtp.isPending,
|
||||
// error: verifyOtp.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useSignOutMutation = () => {
|
||||
const { signOut } = useAuthActions();
|
||||
// export const useSignOutMutation = () => {
|
||||
// const { signOut } = useAuthActions();
|
||||
|
||||
return {
|
||||
signOut: signOut.mutateAsync,
|
||||
isPending: signOut.isPending
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// signOut: signOut.mutateAsync,
|
||||
// isPending: signOut.isPending
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useSendMagicLinkMutation = () => {
|
||||
const { sendMagicLink } = useAuthActions();
|
||||
// export const useSendMagicLinkMutation = () => {
|
||||
// const { sendMagicLink } = useAuthActions();
|
||||
|
||||
return {
|
||||
sendMagicLink: sendMagicLink.mutateAsync,
|
||||
isPending: sendMagicLink.isPending,
|
||||
error: sendMagicLink.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// sendMagicLink: sendMagicLink.mutateAsync,
|
||||
// isPending: sendMagicLink.isPending,
|
||||
// error: sendMagicLink.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useSendPasswordRecoveryMutation = () => {
|
||||
const { sendPasswordRecovery } = useAuthActions();
|
||||
// export const useSendPasswordRecoveryMutation = () => {
|
||||
// const { sendPasswordRecovery } = useAuthActions();
|
||||
|
||||
return {
|
||||
sendPasswordRecovery: sendPasswordRecovery.mutateAsync,
|
||||
isPending: sendPasswordRecovery.isPending,
|
||||
error: sendPasswordRecovery.error,
|
||||
}
|
||||
}
|
||||
// return {
|
||||
// sendPasswordRecovery: sendPasswordRecovery.mutateAsync,
|
||||
// isPending: sendPasswordRecovery.isPending,
|
||||
// error: sendPasswordRecovery.error,
|
||||
// }
|
||||
// }
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { format } from "date-fns";
|
||||
import { redirect } from "next/navigation";
|
||||
import { DateFormatOptions, DateFormatPattern } from "../_lib/types/date-format.interface";
|
||||
import { toast } from "sonner";
|
||||
|
||||
/**
|
||||
* Redirects to a specified path with an encoded message as a query parameter.
|
||||
|
@ -117,4 +118,33 @@ export const formatDate = (
|
|||
return locale
|
||||
? format(dateObj, formatPattern, { locale })
|
||||
: format(dateObj, formatPattern);
|
||||
};
|
||||
|
||||
export const handleCopyItem = (item: string, options?: {
|
||||
onSuccess?: () => void,
|
||||
onError?: (error: unknown) => void
|
||||
}) => {
|
||||
if (!navigator.clipboard) {
|
||||
const error = new Error("Clipboard not supported");
|
||||
toast.error("Clipboard not supported");
|
||||
options?.onError?.(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
const error = new Error("Nothing to copy");
|
||||
toast.error("Nothing to copy");
|
||||
options?.onError?.(error);
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(item)
|
||||
.then(() => {
|
||||
toast.success("Copied to clipboard");
|
||||
options?.onSuccess?.();
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error("Failed to copy to clipboard");
|
||||
options?.onError?.(error);
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue