2025-09-17 18:43:43 +09:00
|
|
|
"use client";
|
|
|
|
|
|
2025-09-20 11:35:40 +09:00
|
|
|
import { SubCard } from "@/components/molecules/SubCard";
|
2025-09-17 18:43:43 +09:00
|
|
|
import { UserIcon, PencilIcon, CheckIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
2025-09-25 15:11:28 +09:00
|
|
|
import type { ProfileEditFormData } from "@customer-portal/domain";
|
2025-09-17 18:43:43 +09:00
|
|
|
|
|
|
|
|
interface PersonalInfoCardProps {
|
2025-09-20 11:35:40 +09:00
|
|
|
data: ProfileEditFormData;
|
2025-09-17 18:43:43 +09:00
|
|
|
isEditing: boolean;
|
|
|
|
|
isSaving: boolean;
|
|
|
|
|
onEdit: () => void;
|
|
|
|
|
onCancel: () => void;
|
2025-09-20 11:35:40 +09:00
|
|
|
onChange: (field: keyof ProfileEditFormData, value: string) => void;
|
2025-09-17 18:43:43 +09:00
|
|
|
onSave: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function PersonalInfoCard({
|
|
|
|
|
data,
|
|
|
|
|
isEditing,
|
|
|
|
|
isSaving,
|
|
|
|
|
onEdit,
|
|
|
|
|
onCancel,
|
|
|
|
|
onChange,
|
|
|
|
|
onSave,
|
|
|
|
|
}: PersonalInfoCardProps) {
|
|
|
|
|
return (
|
|
|
|
|
<SubCard>
|
|
|
|
|
<div className="pb-5 border-b border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<UserIcon className="h-6 w-6 text-blue-600" />
|
|
|
|
|
<h2 className="text-xl font-semibold text-gray-900">Personal Information</h2>
|
|
|
|
|
</div>
|
|
|
|
|
{!isEditing && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={onEdit}
|
|
|
|
|
className="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-lg text-gray-700 bg-white hover:bg-gray-50 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<PencilIcon className="h-4 w-4 mr-2" />
|
|
|
|
|
Edit
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="pt-5">
|
|
|
|
|
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2">
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">First Name</label>
|
|
|
|
|
{isEditing ? (
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={data.firstName}
|
|
|
|
|
onChange={e => onChange("firstName", e.target.value)}
|
|
|
|
|
className="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<p className="text-sm text-gray-900 py-2">
|
|
|
|
|
{data.firstName || <span className="text-gray-500 italic">Not provided</span>}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">Last Name</label>
|
|
|
|
|
{isEditing ? (
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={data.lastName}
|
|
|
|
|
onChange={e => onChange("lastName", e.target.value)}
|
|
|
|
|
className="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<p className="text-sm text-gray-900 py-2">
|
|
|
|
|
{data.lastName || <span className="text-gray-500 italic">Not provided</span>}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="sm:col-span-2">
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-3">Email Address</label>
|
|
|
|
|
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<p className="text-base text-gray-900 font-medium">{data.email}</p>
|
|
|
|
|
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold bg-green-100 text-green-800 border border-green-200">
|
|
|
|
|
<svg className="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
<path
|
|
|
|
|
fillRule="evenodd"
|
|
|
|
|
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
|
|
|
|
clipRule="evenodd"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
Verified
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-xs text-gray-500 mt-2">
|
|
|
|
|
Email cannot be changed. Contact support to update your email.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{isEditing && (
|
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-6 border-t border-gray-200 mt-6">
|
|
|
|
|
<button
|
|
|
|
|
onClick={onCancel}
|
|
|
|
|
disabled={isSaving}
|
|
|
|
|
className="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
|
|
|
|
>
|
|
|
|
|
<XMarkIcon className="h-4 w-4 mr-1" />
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={onSave}
|
|
|
|
|
disabled={isSaving}
|
|
|
|
|
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-50"
|
|
|
|
|
>
|
|
|
|
|
{isSaving ? (
|
|
|
|
|
<>
|
|
|
|
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
|
|
|
|
Saving...
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<CheckIcon className="h-4 w-4 mr-1" />
|
|
|
|
|
Save Changes
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</SubCard>
|
|
|
|
|
);
|
|
|
|
|
}
|