'use client';
import { useState } from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogClose,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { BiX } from 'react-icons/bi';
import { FiEye, FiEyeOff } from 'react-icons/fi';
import { useStudentChangePassword } from '@/lib/api/student';
import { toastUtils } from '@/components/lib/toast';
import { useTranslate } from '@/components/hooks/useTranslate';
interface ChangePasswordModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export default function ChangePasswordModal({
open,
onOpenChange,
}: ChangePasswordModalProps) {
const translate = useTranslate();
// State for password visibility toggles
const [showCurrentPassword, setShowCurrentPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
// State for form values
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
// Change password mutation hook
const changePasswordMutation = useStudentChangePassword();
// Handle form submission
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validation: Check if all fields are filled
if (!currentPassword || !newPassword || !confirmPassword) {
toastUtils.error(translate('pleaseFillInAllFields'));
return;
}
// Validation: Check if new passwords match
if (newPassword !== confirmPassword) {
toastUtils.error(translate('newPasswordsDoNotMatch'));
return;
}
// Validation: Check if new password is different from current password
if (currentPassword === newPassword) {
toastUtils.error(translate('newPasswordMustBeDifferent'));
return;
}
// Validation: Check password length (minimum 6 characters)
if (newPassword.length < 6) {
toastUtils.error(translate('passwordMustBeAtLeast6Characters'));
return;
}
// Call the API to change password
// API will return error code 109 (INVALID_PASSWORD) if current password is wrong
// The mutation hook automatically handles all errors and shows toast messages
changePasswordMutation.mutate(
{
current_password: currentPassword,
new_password: newPassword,
new_confirm_password: confirmPassword,
},
{
onSuccess: () => {
// Reset form fields on success
setCurrentPassword('');
setNewPassword('');
setConfirmPassword('');
// Close the modal
onOpenChange(false);
},
// Error handling is done in the mutation hook
// Errors like "Current password is incorrect" will be shown as toast
}
);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
{/* Modal is responsive: full width with margins on mobile, fixed width on larger screens */}
<DialogContent
className="max-w-[calc(100vw-2rem)] sm:max-w-[550px] p-0"
showCloseButton={false}
>
{/* Header with close button - reduced padding on mobile */}
<DialogHeader className="p-4 pb-3 sm:p-6 sm:pb-4 border-b border-gray-200">
<div className="flex items-start justify-between text-left rtl:text-right">
<div className="flex-1">
{/* Responsive title: smaller on mobile, larger on desktop */}
<DialogTitle className="text-lg sm:text-xl font-bold text-gray-900 mb-1.5 sm:mb-2">
{translate('changeYourPassword')}
</DialogTitle>
{/* Responsive description: smaller text on mobile */}
<DialogDescription className="text-xs sm:text-sm font-normal text-gray-600 leading-relaxed">
{translate('toSecureYourAccountEnterCurrentPassword')}
</DialogDescription>
</div>
{/* Close button: smaller on mobile, normal on desktop */}
<DialogClose asChild>
<button className="ml-2 sm:ml-4 rtl:ml-0 rtl:mr-2 sm:rtl:mr-4 p-1.5 sm:p-2 bg-(--light-primary-color) rounded-[4px] transition-colors border border-gray-200">
<BiX className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
</button>
</DialogClose>
</div>
</DialogHeader>
{/* Form content - reduced padding on mobile */}
<form onSubmit={handleSubmit} className="px-4 pb-4 sm:px-6 sm:pb-6">
{/* Reduced spacing between fields on mobile */}
<div className="space-y-3.5 sm:space-y-5">
{/* Current Password Field */}
<div>
{/* Responsive label: smaller on mobile */}
<label className="block text-sm sm:text-base font-normal text-gray-900 mb-1.5 sm:mb-2">
{translate('currentPassword')}
</label>
<div className="relative">
{/* Responsive input height: shorter on mobile */}
<Input
type={showCurrentPassword ? 'text' : 'password'}
placeholder={translate('enterCurrentPassword')}
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
className="h-11 sm:h-12 pr-10 sm:pr-12 rtl:pr-3 rtl:pl-10 sm:rtl:pl-12 bg-(--light-primary-color) rounded-[4px] shadow-none border border-gray-300 text-gray-900 placeholder:text-gray-400 text-sm sm:text-base"
/>
{/* Responsive eye icon position and size */}
<button
type="button"
onClick={() => setShowCurrentPassword(!showCurrentPassword)}
className="absolute right-2.5 rtl:left-2.5 rtl:right-auto sm:right-3 sm:rtl:left-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
>
{showCurrentPassword ? (
<FiEyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
) : (
<FiEye className="w-4 h-4 sm:w-5 sm:h-5" />
)}
</button>
</div>
</div>
{/* New Password Field */}
<div>
{/* Responsive label: smaller on mobile */}
<label className="block text-sm sm:text-base font-normal text-gray-900 mb-1.5 sm:mb-2">
{translate('newPassword')}
</label>
<div className="relative">
{/* Responsive input height: shorter on mobile */}
<Input
type={showNewPassword ? 'text' : 'password'}
placeholder={translate('enterNewPassword')}
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
className="h-11 sm:h-12 pr-10 sm:pr-12 rtl:pr-3 rtl:pl-10 sm:rtl:pl-12 bg-(--light-primary-color) rounded-[4px] shadow-none border border-gray-300 text-gray-900 placeholder:text-gray-400 text-sm sm:text-base"
/>
{/* Responsive eye icon position and size */}
<button
type="button"
onClick={() => setShowNewPassword(!showNewPassword)}
className="absolute right-2.5 rtl:left-2.5 rtl:right-auto sm:right-3 sm:rtl:left-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
>
{showNewPassword ? (
<FiEyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
) : (
<FiEye className="w-4 h-4 sm:w-5 sm:h-5" />
)}
</button>
</div>
</div>
{/* Confirm New Password Field */}
<div>
{/* Responsive label: smaller on mobile */}
<label className="block text-sm sm:text-base font-normal text-gray-900 mb-1.5 sm:mb-2">
{translate('confirmNewPassword')}
</label>
<div className="relative">
{/* Responsive input height: shorter on mobile */}
<Input
type={showConfirmPassword ? 'text' : 'password'}
placeholder={translate('reEnterNewPassword')}
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="h-11 sm:h-12 pr-10 sm:pr-12 rtl:pr-3 rtl:pl-10 sm:rtl:pl-12 bg-(--light-primary-color) rounded-[4px] shadow-none border border-gray-300 text-gray-900 placeholder:text-gray-400 text-sm sm:text-base"
/>
{/* Responsive eye icon position and size */}
<button
type="button"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
className="absolute right-2.5 rtl:left-2.5 rtl:right-auto sm:right-3 sm:rtl:left-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
>
{showConfirmPassword ? (
<FiEyeOff className="w-4 h-4 sm:w-5 sm:h-5" />
) : (
<FiEye className="w-4 h-4 sm:w-5 sm:h-5" />
)}
</button>
</div>
</div>
{/* Submit Button - responsive height and text size */}
<button
type="submit"
disabled={changePasswordMutation.isPending}
className="w-full h-11 sm:h-12 bg-(--primary-color) text-white text-base sm:text-xl font-normal rounded-[4px] mt-1.5 sm:mt-2 disabled:opacity-50 disabled:cursor-not-allowed transition-opacity"
>
{changePasswordMutation.isPending
? translate('changingPassword')
: translate('changePassword')}
</button>
</div>
</form>
</DialogContent>
</Dialog>
);
}