update-full

This commit is contained in:
TuanVT
2026-06-06 01:02:07 +07:00
parent 7791e1d6a8
commit d4194d6f12
30 changed files with 1018 additions and 391 deletions
+79 -163
View File
@@ -1,97 +1,94 @@
"use client";
import React, { useEffect, useState } from "react";
import React, { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { LockKeyhole, ShieldPlus, User } from "lucide-react";
import { ShieldPlus, User } from "lucide-react";
import { useSelector } from "react-redux";
import { RootState, store } from "@/redux/store";
import {
setDataLoginStorage,
setStateLogin,
setToken,
} from "@/redux/reducer/auth";
import { setRememberPassword } from "@/redux/reducer/site";
import { setInfoUser } from "@/redux/reducer/user";
import authServices from "@/services/authServices";
import authServices, { LoginResponse } from "@/services/authServices";
import { httpRequest } from "@/services";
import { PATH } from "@/constant/config";
import FormCustom from "@/components/utils/FormCustom";
import InputForm from "@/components/utils/FormCustom/components/InputForm";
import CustomLoading from "@/components/customs/custom-loading";
import CustomButton from "@/components/customs/custom-button";
import { ContextFormCustom } from "@/components/utils/FormCustom/contexts";
export default function MainLogin() {
const router = useRouter();
const { dataLoginStorage } = useSelector((state: RootState) => state.auth);
const { isRememberPassword } = useSelector((state: RootState) => state.site);
const [form, setForm] = useState({
// Khởi tạo state form từ data lưu trữ
const [form, setForm] = useState(() => ({
username: isRememberPassword ? dataLoginStorage?.usernameStorage || "" : "",
password: isRememberPassword ? dataLoginStorage?.passwordStorage || "" : "",
}));
deviceId: isRememberPassword ? dataLoginStorage?.deviceIdStorage || "" : "",
});
const loginMutation = useMutation({
const loginMutation = useMutation<LoginResponse>({
mutationFn: async () => {
return httpRequest({
showMessageFailed: true,
showMessageSuccess: true,
msgSuccess: "Đăng nhập thành công!",
return (await httpRequest({
http: authServices.login({
username: form.username,
password: form.password,
deviceId: form.username,
deviceId: "Browser-Chrome-Windowns",
}),
});
})) as LoginResponse;
},
onSuccess(data: any) {
if (!data) return;
store.dispatch(setStateLogin(true));
store.dispatch(setToken(data.token));
store.dispatch(
setInfoUser({
accessToken: data?.token || "",
refreshToken: data?.refreshToken || "",
accessExpiresAt: data?.accessExpiresAt || "",
refreshExpiresAt: data?.refreshExpiresAt || "",
avatar: data?.avatar || "",
fullname: data?.fullname || "",
}),
);
if (isRememberPassword) {
onSuccess(data) {
if (data) {
store.dispatch(setToken(data?.token));
store.dispatch(
setDataLoginStorage({
usernameStorage: form.username,
passwordStorage: form.password,
deviceIdStorage: form.deviceId,
setInfoUser({
accessToken: data?.token || "",
refreshToken: data?.refreshToken || "",
userId: data?.userId || "",
}),
);
} else {
store.dispatch(setDataLoginStorage(null));
}
store.dispatch(setStateLogin(true));
router.replace(PATH.HOME);
if (isRememberPassword) {
store.dispatch(
setDataLoginStorage({
usernameStorage: form.username,
passwordStorage: form.password,
}),
);
} else {
store.dispatch(setDataLoginStorage(null));
}
router.replace(PATH.HOME, undefined);
}
},
});
const handleLogin = () => {
// Kiểm tra nhanh điều kiện dữ liệu trước khi trigger API
if (!form.username || !form.password) return;
if (isRememberPassword) {
store.dispatch(
setDataLoginStorage({
usernameStorage: form.username,
passwordStorage: form.password,
}),
);
} else {
store.dispatch(setDataLoginStorage(null));
}
loginMutation.mutate();
};
@@ -101,24 +98,8 @@ export default function MainLogin() {
<FormCustom form={form} setForm={setForm} onSubmit={handleLogin}>
{/* TITLE */}
<h3
className="
text-[34px]
font-semibold
text-[#1A1B2D]
"
>
Đăng nhập
</h3>
<p
className="
mt-1
text-[14px]
font-medium
text-[#6F767E]
"
>
<h3 className="text-[34px] font-semibold text-[#1A1B2D]">Đăng nhập</h3>
<p className="mt-1 text-[14px] font-medium text-[#6F767E]">
Chào mừng bạn đến với hệ thống quản
</p>
@@ -128,8 +109,7 @@ export default function MainLogin() {
<InputForm
label={
<span>
Tài khoản
<span className="text-red-500"> *</span>
Tài khoản<span className="text-red-500"> *</span>
</span>
}
placeholder="Tài khoản"
@@ -142,32 +122,12 @@ export default function MainLogin() {
icon={<User size={22} />}
/>
{/* <div className="mt-5">
<InputForm
label={
<span>
deviceId
<span className="text-red-500"> *</span>
</span>
}
placeholder="deviceId"
type="text"
name="deviceId"
onClean
isRequired
isBlur
showDone
icon={<ShieldPlus size={22} />}
/>
</div> */}
{/* PASSWORD */}
<div className="mt-5">
<InputForm
label={
<span>
Mật khẩu
<span className="text-red-500"> *</span>
Mật khẩu<span className="text-red-500"> *</span>
</span>
}
placeholder="Mật khẩu"
@@ -182,15 +142,7 @@ export default function MainLogin() {
</div>
{/* REMEMBER PASSWORD */}
<div
className="
mt-[14px]
flex
items-center
gap-2
cursor-pointer
"
>
<div className="mt-[14px] flex items-center gap-2 cursor-pointer">
<input
id="rememberPassword"
type="checkbox"
@@ -198,23 +150,11 @@ export default function MainLogin() {
onChange={() =>
store.dispatch(setRememberPassword(!isRememberPassword))
}
className="
h-5
w-5
cursor-pointer
accent-[#0011AB]
"
className="h-5 w-5 cursor-pointer accent-[#0011AB]"
/>
<label
htmlFor="rememberPassword"
className="
cursor-pointer
select-none
text-[14px]
font-medium
text-[#171717]
"
className="cursor-pointer select-none text-[14px] font-medium text-[#171717]"
>
Nhớ mật khẩu
</label>
@@ -223,64 +163,40 @@ export default function MainLogin() {
{/* BUTTONS */}
<div className="mt-6">
<div className="flex gap-2">
{/* LOGIN */}
<CustomButton
variant="midnightBlue"
disabled={loginMutation.isPending}
rounded="full"
type="submit"
className="font-bold text-2xl disabled:cursor-not-allowed
disabled:opacity-50 h-[52px]"
>
Đăng nhập
</CustomButton>
{/* REGISTER */}
{/* LOGIN BUTTON */}
<ContextFormCustom.Consumer>
{({ isDone }) => {
// Tự kiểm tra xem form hiện tại đã có sẵn dữ liệu hợp lệ chưa
const hasRememberedData = !!(form.username && form.password);
// Sáng nút nếu FormCustom báo Done HOẶC form đã có sẵn dữ liệu từ Redux
const canSubmit = isDone || hasRememberedData;
return (
<CustomButton
variant="midnightBlue"
disabled={!canSubmit}
rounded="full"
type="button" // Chuyển từ "submit" sang "button" để tránh bị FormCustom chặn
onClick={handleLogin} // Gọi trực tiếp hàm submit khi click
className="font-bold text-2xl disabled:cursor-not-allowed disabled:opacity-50 h-[52px]"
>
Đăng nhập
</CustomButton>
);
}}
</ContextFormCustom.Consumer>
{/* REGISTER BUTTON */}
<CustomButton
variant="default"
rounded="full"
className="font-bold text-2xl disabled:cursor-not-allowed
disabled:opacity-50 h-[52px]"
className="font-bold text-2xl disabled:cursor-not-allowed disabled:opacity-50 h-[52px]"
onClick={() => router.push(PATH.REGISTER)}
>
Đăng
</CustomButton>
</div>
{/* LINE */}
{/* <div
className="
my-5
h-[1px]
w-full
bg-[#E5E5E5]
"
/> */}
{/* FORGOT PASSWORD */}
{/* <button
type="button"
onClick={() => router.push(PATH.FORGOT_PASSWORD)}
className="
flex
h-[52px]
w-full
items-center
justify-center
gap-2
rounded-full
border
border-gray-300
bg-white
px-6
font-bold
text-[#171717]
transition-all
hover:bg-gray-50
"
>
<LockKeyhole size={22} />
Quên mật khẩu
</button> */}
</div>
</div>
</FormCustom>