Commit 513e88f6 authored by ThinhNC's avatar ThinhNC

feat(handover): display masked email and instructions for production OTP verification

parent 68d16cdd
......@@ -391,5 +391,24 @@ export const DownloadIcon: React.FC<IconProps> = ({ size = 20, ...props }) => (
</svg>
);
// Mail / Email Icon
export const MailIcon: React.FC<IconProps> = ({ size = 20, ...props }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<rect width="20" height="16" x="2" y="4" rx="2" />
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
</svg>
);
......@@ -2453,6 +2453,7 @@
"warningNotice2": "All wallets, income/expense history, budgets, and goals will be permanently moved to the new Zalo account.",
"warningNotice3": "Your current account will be immediately logged out and securely locked.",
"warningNotice4": "The QR code and PIN code will automatically expire after 15 minutes.",
"warningNoticeEmail": "An email address must be linked to your account to receive the transfer authorization OTP.",
"btnInitiate": "Create Code",
"initiateSuccess": "Handover session created successfully",
"timeLeft": "Time remaining:",
......@@ -2464,6 +2465,8 @@
"cancelled": "Handover session cancelled",
"targetConnected": "New Account Connected!",
"otpAuthNotice": "Two-way Mutual Authorization:",
"otpEmailSentTitle": "OTP Sent to Email",
"otpEmailSentDesc": "Check your inbox (or Spam/Junk folder) of:",
"otpInputLabel": "OTP Authorization Code (6 digits)",
"otpRequired": "Please enter the 6-digit OTP code",
"btnConfirmOtp": "Authorize & Transfer Data Now",
......
......@@ -2554,6 +2554,7 @@
"warningNotice2": "Toàn bộ ví tiền, lịch sử thu chi, ngân sách, mục tiêu sẽ được chuyển vĩnh viễn sang tài khoản Zalo mới.",
"warningNotice3": "Tài khoản hiện tại sẽ tự động đăng xuất và bị khóa an toàn.",
"warningNotice4": "Mã QR và mã PIN sẽ tự động hết hạn sau 15 phút.",
"warningNoticeEmail": "Tài khoản cần có liên kết Email để nhận mã xác thực OTP ký duyệt chuyển giao.",
"btnInitiate": "Tạo Mã",
"initiateSuccess": "Đã tạo mã chuyển giao thành công",
"timeLeft": "Hiệu lực mã:",
......@@ -2565,6 +2566,8 @@
"cancelled": "Đã hủy phiên chuyển giao",
"targetConnected": "Tài Khoản Mới Đã Kết Nối!",
"otpAuthNotice": "Xác thực bảo mật 2 chiều:",
"otpEmailSentTitle": "Đã gửi mã OTP qua Email",
"otpEmailSentDesc": "Kiểm tra hộp thư đến (hoặc hòm thư Rác/Spam) của:",
"otpInputLabel": "Mã xác thực OTP (6 chữ số)",
"otpRequired": "Vui lòng nhập mã OTP gồm 6 chữ số",
"btnConfirmOtp": "Ký Duyệt & Chuyển Dữ Liệu Ngay",
......
......@@ -24,6 +24,7 @@ import {
TransferIcon,
BudgetIcon,
SavingGoalIcon,
MailIcon,
} from "@/components/ui/icons";
import { useAuthStore } from "@/stores/auth-store";
import { handoverService } from "@/services/handover.service";
......@@ -57,6 +58,7 @@ export const AccountHandoverPage: React.FC = () => {
const [targetUserName, setTargetUserName] = useState<string>("");
const [otpPrompt, setOtpPrompt] = useState<string>("");
const [otpDevCode, setOtpDevCode] = useState<string>("");
const [maskedEmail, setMaskedEmail] = useState<string>("");
const [otpInput, setOtpInput] = useState<string>("");
const [senderTimeLeft, setSenderTimeLeft] = useState<number>(900);
const [isInitiating, setIsInitiating] = useState<boolean>(false);
......@@ -162,6 +164,7 @@ export const AccountHandoverPage: React.FC = () => {
if (statusRes.targetUserName) setTargetUserName(statusRes.targetUserName);
if (statusRes.otpPrompt) setOtpPrompt(statusRes.otpPrompt);
if (statusRes.otpCodeDev) setOtpDevCode(statusRes.otpCodeDev);
if (statusRes.sourceUserEmailMasked) setMaskedEmail(statusRes.sourceUserEmailMasked);
} else if (statusRes.status === "EXPIRED") {
setSenderStatus("EXPIRED");
}
......@@ -222,6 +225,7 @@ export const AccountHandoverPage: React.FC = () => {
setSenderStatus("IDLE");
setInitiateData(null);
setOtpInput("");
setMaskedEmail("");
openSnackbar({
type: "info",
text: t("handover.cancelled") || "Đã hủy phiên chuyển giao",
......@@ -461,6 +465,10 @@ export const AccountHandoverPage: React.FC = () => {
{t("handover.warningNotice4") ||
"Mã QR và mã PIN sẽ tự động hết hạn sau 15 phút."}
</li>
<li>
{t("handover.warningNoticeEmail") ||
"Tài khoản cần có liên kết Email để nhận mã xác thực OTP ký duyệt chuyển giao."}
</li>
</ul>
</div>
</div>
......@@ -619,6 +627,22 @@ export const AccountHandoverPage: React.FC = () => {
</div>
</div>
{/* Email Sent Banner (Production / Real Flow) */}
{maskedEmail && (
<div className="p-3.5 rounded-clay-sm bg-clay-income/10 border border-clay-income/25 flex items-start gap-2.5">
<MailIcon size={18} className="text-clay-income-dark shrink-0 mt-0.5" />
<div className="text-xs text-clay-text leading-relaxed">
<span className="font-bold text-clay-income-dark block">
{t("handover.otpEmailSentTitle") || "Đã gửi mã OTP qua Email"}
</span>
<span>
{t("handover.otpEmailSentDesc") || "Kiểm tra hộp thư đến (hoặc hòm thư Rác/Spam) của:"}{" "}
<strong className="text-clay-primary font-bold">{maskedEmail}</strong>
</span>
</div>
</div>
)}
{/* Sandbox / Dev OTP Code Notice (if present) */}
{otpDevCode && (
<div className="p-2.5 rounded-clay-sm bg-clay-income/15 border border-clay-income/30 text-center">
......
......@@ -35,6 +35,7 @@ export interface HandoverStatusResponse {
targetUserName?: string | null;
otpPrompt?: string;
otpCodeDev?: string;
sourceUserEmailMasked?: string;
}
export interface ClaimHandoverRequest {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment