doctor-mail/apps/web/src/app/auth/register.tsx

203 lines
9.3 KiB
TypeScript
Raw Normal View History

2025-01-22 23:19:58 +08:00
import { motion } from "framer-motion";
// RegisterForm.tsx
export const RegisterForm = ({ form, onSubmit, isLoading }) => {
const { register, handleSubmit, formState: { errors }, watch } = form;
const password = watch("password");
return (
<motion.form
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="space-y-6"
onSubmit={handleSubmit(onSubmit)}
>
<h2 className="text-2xl font-bold text-white text-center mb-8">
Create Account
</h2>
<div className="space-y-4">
{/* Department Selection */}
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Department
</label>
<select
{...register("deptId", { required: "Department is required" })}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
>
<option value="">Select Department</option>
<option value="AF-HQ">Air Force Headquarters</option>
<option value="AF-OPS">Operations Command</option>
<option value="AF-LOG">Logistics Command</option>
<option value="AF-TRN">Training Command</option>
</select>
{errors.deptId && (
<span className="text-red-400 text-sm mt-1">
{errors.deptId.message}
</span>
)}
</div>
{/* User Information Row */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Username
</label>
<input
{...register("username", {
required: "Username is required",
minLength: {
value: 2,
message: "Username must be at least 2 characters"
},
pattern: {
value: /^[a-zA-Z0-9._-]+$/,
message: "Username can only contain letters, numbers, and ._-"
}
})}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
placeholder="Username"
/>
{errors.username && (
<span className="text-red-400 text-sm mt-1">
{errors.username.message}
</span>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Full Name
</label>
<input
{...register("showname", {
required: "Full name is required",
minLength: {
value: 2,
message: "Name must be at least 2 characters"
}
})}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
placeholder="Full Name"
/>
{errors.showname && (
<span className="text-red-400 text-sm mt-1">
{errors.showname.message}
</span>
)}
</div>
</div>
{/* Service ID */}
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Service ID
</label>
<input
{...register("officerId", {
required: "Service ID is required",
pattern: {
value: /^\d{5,12}$/,
message: "Please enter a valid Service ID (5-12 digits)"
}
})}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
placeholder="Service ID"
/>
{errors.officerId && (
<span className="text-red-400 text-sm mt-1">
{errors.officerId.message}
</span>
)}
</div>
{/* Password Fields */}
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Password
</label>
<input
type="password"
{...register("password", {
required: "Password is required",
minLength: {
value: 8,
message: "Password must be at least 8 characters"
},
pattern: {
value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
message: "Password must contain uppercase, lowercase, number and special character"
}
})}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
placeholder="Password"
/>
{errors.password && (
<span className="text-red-400 text-sm mt-1">
{errors.password.message}
</span>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-300 mb-1">
Confirm Password
</label>
<input
type="password"
{...register("repeatPass", {
required: "Please confirm your password",
validate: value => value === password || "Passwords do not match"
})}
className="w-full px-4 py-2 bg-white/10 border border-gray-600
rounded-lg focus:ring-2 focus:ring-blue-500
text-white placeholder-gray-400"
placeholder="Confirm Password"
/>
{errors.repeatPass && (
<span className="text-red-400 text-sm mt-1">
{errors.repeatPass.message}
</span>
)}
</div>
</div>
</div>
{/* Submit Button */}
<button
type="submit"
disabled={isLoading}
className="w-full py-3 px-4 bg-blue-600 text-white rounded-lg
hover:bg-blue-700 transition-colors duration-300
disabled:opacity-50 disabled:cursor-not-allowed
flex items-center justify-center space-x-2"
>
{isLoading ? (
<>
<svg className="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>Creating Account...</span>
</>
) : (
<span>Create Account</span>
)}
</button>
</motion.form>
);
};