Corp/frontend/src/components/users/EditUserProfileModal.tsx
2026-04-02 10:32:24 +03:00

237 lines
9.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import type { ChangeEvent } from "react";
import { X } from "lucide-react";
import type { User } from "@/types/api";
import type { UserProfileEditForm, UserProfileTextField } from "@/lib/users/userDetailUtils";
type EditUserProfileModalProps = {
actionLoading: string | null;
avatarFailed: boolean;
avatarUrl: string | null;
form: UserProfileEditForm;
initials: string;
isOpen: boolean;
onAvatarChange: (event: ChangeEvent<HTMLInputElement>) => void;
onClose: () => void;
onSave: () => void;
onTextFieldChange: (field: UserProfileTextField, value: string) => void;
person: User | null;
};
export default function EditUserProfileModal({
actionLoading,
avatarFailed,
avatarUrl,
form,
initials,
isOpen,
onAvatarChange,
onClose,
onSave,
onTextFieldChange,
person,
}: EditUserProfileModalProps) {
if (!isOpen || !person) {
return null;
}
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
<div className="max-h-[90vh] w-full max-w-2xl overflow-y-auto rounded-2xl bg-white p-6 shadow-xl">
<div className="mb-4 flex items-center justify-between">
<h2 className="text-xl font-bold text-gray-900">Редактировать профиль</h2>
<button
type="button"
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
disabled={actionLoading === "edit"}
>
<X size={24} />
</button>
</div>
<div className="space-y-4">
<div>
<label className="mb-2 block text-sm font-medium text-gray-700">
Аватар
</label>
<div className="flex items-center gap-4">
<div className="flex h-20 w-20 items-center justify-center overflow-hidden rounded-full bg-sky-400 text-xl font-semibold text-white">
{form.avatarPreview ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={form.avatarPreview}
alt="Preview"
className="h-full w-full object-cover"
/>
) : avatarUrl && !avatarFailed ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={avatarUrl}
alt="Avatar"
className="h-full w-full object-cover"
/>
) : (
<span>{initials}</span>
)}
</div>
<label className="cursor-pointer rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50">
<input
type="file"
accept="image/*"
onChange={onAvatarChange}
className="hidden"
/>
Загрузить
</label>
</div>
<p className="mt-1 text-xs text-gray-500">
Максимальный размер: 5MB. Форматы: JPG, PNG, GIF
</p>
</div>
<div className="grid gap-4 sm:grid-cols-3">
<div>
<label htmlFor="edit-last-name" className="mb-2 block text-sm font-medium text-gray-700">
Фамилия *
</label>
<input
id="edit-last-name"
type="text"
value={form.lastName}
onChange={(event) => onTextFieldChange("lastName", event.target.value)}
placeholder="Иванов"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
maxLength={150}
/>
</div>
<div>
<label htmlFor="edit-first-name" className="mb-2 block text-sm font-medium text-gray-700">
Имя *
</label>
<input
id="edit-first-name"
type="text"
value={form.firstName}
onChange={(event) => onTextFieldChange("firstName", event.target.value)}
placeholder="Иван"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
maxLength={150}
/>
</div>
<div>
<label htmlFor="edit-patronymic" className="mb-2 block text-sm font-medium text-gray-700">
Отчество
</label>
<input
id="edit-patronymic"
type="text"
value={form.patronymic}
onChange={(event) => onTextFieldChange("patronymic", event.target.value)}
placeholder="Иванович"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
maxLength={150}
/>
</div>
</div>
<div className="grid gap-4 sm:grid-cols-2">
<div>
<label htmlFor="edit-email" className="mb-2 block text-sm font-medium text-gray-700">
Email *
</label>
<input
id="edit-email"
type="email"
value={form.email}
onChange={(event) => onTextFieldChange("email", event.target.value)}
placeholder="ivan@example.com"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
/>
</div>
<div>
<label htmlFor="edit-phone" className="mb-2 block text-sm font-medium text-gray-700">
Телефон
</label>
<input
id="edit-phone"
type="tel"
value={form.phone}
onChange={(event) => onTextFieldChange("phone", event.target.value)}
placeholder="+7 999 123-45-67"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
/>
</div>
</div>
<div className="grid gap-4 sm:grid-cols-3">
<div>
<label htmlFor="edit-telegram" className="mb-2 block text-sm font-medium text-gray-700">
Telegram
</label>
<input
id="edit-telegram"
type="text"
value={form.telegram}
onChange={(event) => onTextFieldChange("telegram", event.target.value)}
placeholder="@username"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
/>
</div>
<div>
<label htmlFor="edit-whatsapp" className="mb-2 block text-sm font-medium text-gray-700">
WhatsApp
</label>
<input
id="edit-whatsapp"
type="tel"
value={form.whatsapp}
onChange={(event) => onTextFieldChange("whatsapp", event.target.value)}
placeholder="+7 999 123-45-67"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
/>
</div>
<div>
<label htmlFor="edit-wechat" className="mb-2 block text-sm font-medium text-gray-700">
WeChat
</label>
<input
id="edit-wechat"
type="text"
value={form.wechat}
onChange={(event) => onTextFieldChange("wechat", event.target.value)}
placeholder="username"
className="w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/20"
/>
</div>
</div>
</div>
<div className="mt-6 flex gap-3">
<button
type="button"
onClick={onClose}
disabled={actionLoading === "edit"}
className="flex-1 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50 disabled:opacity-50"
>
Отмена
</button>
<button
type="button"
onClick={onSave}
disabled={actionLoading === "edit" || !form.firstName.trim() || !form.lastName.trim() || !form.email.trim()}
className="flex-1 rounded-lg bg-sky-600 px-4 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-sky-700 disabled:opacity-50"
>
{actionLoading === "edit" ? "Сохранение..." : "Сохранить"}
</button>
</div>
</div>
</div>
);
}