import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useMemo, useRef, useState } from "react"; import styled from "styled-components"; import { uploadAvatar, listAvatars, createParent, updateParent, createGrandParent, updateGrandParent } from "../services/api-client"; const Panel = styled.aside ` flex: 1; padding: 24px; border-radius: 18px; background: rgba(29, 36, 66, 0.92); border: 1px solid rgba(126, 136, 180, 0.22); display: flex; flex-direction: column; gap: 20px; `; const Title = styled.h2 ` margin: 0; `; const Description = styled.p ` margin: 0; color: var(--text-muted); `; const Form = styled.form ` display: flex; flex-direction: column; gap: 18px; `; const Label = styled.label ` display: flex; flex-direction: column; gap: 8px; font-weight: 600; `; const Row = styled.div ` display: flex; gap: 12px; flex-wrap: wrap; `; const BaseInput = styled.input ` padding: 12px 14px; border-radius: 12px; border: 1px solid rgba(126, 136, 180, 0.28); background: rgba(16, 22, 52, 0.9); color: #ffffff; `; const TextArea = styled.textarea ` padding: 12px 14px; border-radius: 12px; border: 1px solid rgba(126, 136, 180, 0.28); min-height: 96px; background: rgba(16, 22, 52, 0.9); color: #ffffff; `; const SubmitButton = styled.button ` padding: 12px 16px; border-radius: 12px; border: none; background: ${({ $loading }) => $loading ? "rgba(85, 98, 255, 0.25)" : "linear-gradient(135deg, #5562ff, #7d6cff)"}; color: #ffffff; font-weight: 600; cursor: ${({ $loading }) => ($loading ? "progress" : "pointer")}; display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: opacity 0.2s ease; opacity: ${({ $loading }) => ($loading ? 0.7 : 1)}; `; const SecondaryButton = styled.button ` padding: 12px 16px; border-radius: 12px; border: 1px solid rgba(126, 136, 180, 0.4); background: rgba(16, 22, 52, 0.9); color: #d9dcff; font-weight: 600; cursor: pointer; transition: transform 0.2s ease; &:hover { transform: translateY(-1px); } `; const AvatarSection = styled.section ` display: flex; flex-direction: column; gap: 16px; `; const AvatarHeader = styled.div ` display: flex; align-items: center; justify-content: space-between; `; const AvatarPreview = styled.div ` display: flex; gap: 12px; align-items: center; `; const AvatarImage = styled.img ` width: 72px; height: 72px; border-radius: 18px; object-fit: cover; border: 2px solid rgba(126, 136, 180, 0.28); `; const AvatarFallback = styled.div ` width: 72px; height: 72px; border-radius: 18px; display: flex; align-items: center; justify-content: center; background: rgba(9, 13, 28, 0.8); border: 2px solid ${({ $color }) => $color}; color: #f4f5ff; font-weight: 700; `; const AvatarInfo = styled.div ` display: flex; flex-direction: column; gap: 4px; `; const Helper = styled.span ` color: var(--text-muted); font-size: 0.9rem; `; const AvatarPicker = styled.div ` display: grid; grid-template-columns: 1fr 1fr; gap: 16px; `; const StatusMessage = styled.div ` padding: 12px; border-radius: 12px; border: 1px solid rgba(126, 136, 180, 0.3); background: rgba(16, 22, 52, 0.7); color: var(--text-muted); `; const GalleryGrid = styled.div ` display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 12px; `; const GalleryItem = styled.button ` border: 2px solid ${({ $selected }) => ($selected ? "#5562ff" : "transparent")}; border-radius: 12px; overflow: hidden; background: rgba(9, 13, 28, 0.8); cursor: pointer; `; const GalleryThumbnail = styled.img ` display: block; width: 100%; height: 100%; object-fit: cover; `; const ErrorText = styled.div ` color: #ffb3bd; `; const DEFAULT_COLOR = "#7d6cff"; export const ParentProfilePanel = ({ mode = "create", parent, onCancel, kind = "parent" }) => { const isEdit = mode === "edit" && !!parent; const resolvedKind = kind; const createEntity = resolvedKind === 'grandparent' ? createGrandParent : createParent; const updateEntity = resolvedKind === 'grandparent' ? updateGrandParent : updateParent; const displayLabel = resolvedKind === 'grandparent' ? 'grand-parent' : 'parent'; const [fullName, setFullName] = useState(""); const [email, setEmail] = useState(""); const [colorHex, setColorHex] = useState(DEFAULT_COLOR); const [notes, setNotes] = useState(""); const [avatarSelection, setAvatarSelection] = useState(null); const [removeExistingAvatar, setRemoveExistingAvatar] = useState(false); const [avatarPickerOpen, setAvatarPickerOpen] = useState(false); const [gallery, setGallery] = useState([]); const [galleryLoading, setGalleryLoading] = useState(false); const [galleryError, setGalleryError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const fileInputRef = useRef(null); useEffect(() => { if (avatarPickerOpen && gallery.length === 0 && !galleryLoading) { setGalleryLoading(true); listAvatars() .then((list) => setGallery(list.map((g) => ({ filename: g.filename, url: g.url })))) .catch(() => setGalleryError("Impossible de charger la galerie locale.")) .finally(() => setGalleryLoading(false)); } }, [avatarPickerOpen, gallery.length, galleryLoading]); useEffect(() => { if (isEdit && parent) { setFullName(parent.fullName); setColorHex(parent.colorHex); setEmail(parent.email ?? ""); setNotes(parent.notes ?? ""); setAvatarSelection(null); setRemoveExistingAvatar(false); if (fileInputRef.current) fileInputRef.current.value = ""; setError(null); } else if (!isEdit) { setFullName(""); setColorHex(DEFAULT_COLOR); setEmail(""); setNotes(""); setAvatarSelection(null); setRemoveExistingAvatar(false); if (fileInputRef.current) fileInputRef.current.value = ""; setError(null); } }, [isEdit, parent]); const initials = useMemo(() => { return fullName .split(" ") .filter(Boolean) .map((part) => part.charAt(0)) .join("") .slice(0, 2) .toUpperCase(); }, [fullName]); const currentAvatarUrl = useMemo(() => { if (avatarSelection) { return avatarSelection.source === "upload" ? avatarSelection.previewUrl : avatarSelection.url; } if (removeExistingAvatar) return null; return parent?.avatar?.url ?? null; }, [avatarSelection, parent?.avatar, removeExistingAvatar]); const currentAvatarLabel = useMemo(() => { if (avatarSelection) { return avatarSelection.source === "upload" ? avatarSelection.name : avatarSelection.name ?? "Avatar local"; } if (removeExistingAvatar) return "Aucun avatar selectionne"; return parent?.avatar?.name ?? "Aucun avatar selectionne"; }, [avatarSelection, parent?.avatar, removeExistingAvatar]); const handleFileChange = (event) => { const file = event.target.files?.[0]; if (!file) return; if (!file.type.startsWith("image/")) { setError("Le fichier doit etre une image (png, jpg, svg...)."); return; } setAvatarSelection({ source: "upload", file, previewUrl: URL.createObjectURL(file), name: file.name }); setRemoveExistingAvatar(false); setError(null); }; const handleSelectGallery = (item) => { setAvatarSelection({ source: "gallery", url: item.url, name: item.filename }); setRemoveExistingAvatar(false); if (fileInputRef.current) fileInputRef.current.value = ""; }; const handleClearAvatar = () => { if (avatarSelection?.source === "upload") URL.revokeObjectURL(avatarSelection.previewUrl); setAvatarSelection(null); if (fileInputRef.current) fileInputRef.current.value = ""; setRemoveExistingAvatar(isEdit); }; const handleSubmit = async (event) => { event.preventDefault(); if (isSubmitting) return; if (!fullName.trim()) { setError("Merci de saisir le nom complet."); return; } const payload = { fullName: fullName.trim(), colorHex, email: email.trim() ? email.trim() : undefined, notes: notes.trim() ? notes.trim() : undefined }; setIsSubmitting(true); setError(null); try { let avatarPayload = undefined; if (avatarSelection?.source === "upload") { const uploaded = await uploadAvatar(avatarSelection.file); avatarPayload = { kind: "custom", url: uploaded.url, name: avatarSelection.name }; URL.revokeObjectURL(avatarSelection.previewUrl); setAvatarSelection({ source: "gallery", url: uploaded.url, name: avatarSelection.name }); } else if (avatarSelection?.source === "gallery") { avatarPayload = { kind: "custom", url: avatarSelection.url, name: avatarSelection.name }; } else if (isEdit && parent?.avatar && !removeExistingAvatar) { avatarPayload = parent.avatar; } else if (removeExistingAvatar) { avatarPayload = null; } if (avatarPayload !== undefined) { payload.avatar = avatarPayload ?? undefined; } if (isEdit && parent) { await updateEntity(parent.id, payload); onCancel?.(); } else { await createEntity(payload); setFullName(""); setColorHex(DEFAULT_COLOR); setEmail(""); setNotes(""); setAvatarSelection(null); setRemoveExistingAvatar(false); if (fileInputRef.current) fileInputRef.current.value = ""; } } catch (err) { setError("Impossible d enregistrer pour le moment. Merci de reessayer."); } finally { setIsSubmitting(false); } }; return (_jsxs(Panel, { children: [_jsx(Title, { children: isEdit ? "Modifier le parent" : "Ajouter un parent" }), _jsx(Description, { children: isEdit ? "Ajuste le profil, la couleur ou l avatar. Les modifications sont visibles partout." : "Cree rapidement un nouveau profil en renseignant email et avatar." }), _jsxs(Form, { onSubmit: handleSubmit, children: [_jsxs(Label, { children: ["Prenom et nom", _jsx(BaseInput, { type: "text", placeholder: "Ex: Jean Dupont", value: fullName, onChange: (event) => setFullName(event.target.value) })] }), _jsxs(Row, { children: [_jsxs(Label, { style: { flex: "1 1 180px" }, children: ["Adresse email", _jsx(BaseInput, { type: "email", placeholder: "prenom@exemple.com", value: email, onChange: (event) => setEmail(event.target.value) })] }), _jsxs(Label, { style: { width: "120px" }, children: ["Couleur", _jsx(BaseInput, { type: "color", value: colorHex, onChange: (event) => setColorHex(event.target.value) })] })] }), _jsxs(Label, { children: ["Notes", _jsx(TextArea, { placeholder: "Infos importantes, telephone...", value: notes, onChange: (event) => setNotes(event.target.value) })] }), _jsxs(AvatarSection, { children: [_jsxs(AvatarHeader, { children: [_jsx("strong", { children: "Avatar" }), _jsxs(Row, { children: [_jsx(SecondaryButton, { type: "button", onClick: () => setAvatarPickerOpen((o) => !o), children: avatarPickerOpen ? "Fermer" : "Choisir un avatar" }), (avatarSelection || (isEdit && parent?.avatar && !removeExistingAvatar)) && (_jsx(SecondaryButton, { type: "button", onClick: handleClearAvatar, children: "Retirer l avatar" }))] })] }), _jsxs(AvatarPreview, { children: [currentAvatarUrl ? (_jsx(AvatarImage, { src: currentAvatarUrl, alt: currentAvatarLabel ?? "Avatar" })) : (_jsx(AvatarFallback, { "$color": colorHex, children: initials || "?" })), _jsxs(AvatarInfo, { children: [_jsx("span", { children: currentAvatarLabel }), _jsx(Helper, { children: "Les avatars importes sont stockes dans `backend/public/avatars/`." })] })] }), avatarPickerOpen ? (_jsxs(AvatarPicker, { children: [_jsxs("div", { children: [_jsx("strong", { children: "Importer un nouvel avatar" }), _jsx(Label, { children: _jsx(BaseInput, { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleFileChange }) }), _jsx(Helper, { children: "Formats acceptes: png, jpg, svg. Taille conseillee 512x512. Les images importees sont stockees localement." })] }), _jsxs("div", { children: [_jsx("strong", { children: "Galerie locale" }), galleryLoading ? (_jsx(StatusMessage, { children: "Chargement de la galerie..." })) : galleryError ? (_jsx(StatusMessage, { children: galleryError })) : gallery.length === 0 ? (_jsx(StatusMessage, { children: "Aucune image dans `backend/public/avatars/`. Ajoute des fichiers pour les proposer ici." })) : (_jsx(GalleryGrid, { children: gallery.map((item) => (_jsx(GalleryItem, { "$selected": avatarSelection?.source === "gallery" && avatarSelection.url === item.url, type: "button", onClick: () => handleSelectGallery(item), children: _jsx(GalleryThumbnail, { src: item.url, alt: item.filename }) }, item.filename))) }))] })] })) : null] }), error ? _jsx(ErrorText, { children: error }) : null, _jsxs(Row, { children: [_jsx(SubmitButton, { type: "submit", disabled: isSubmitting, "$loading": isSubmitting, children: isSubmitting ? "Enregistrement..." : isEdit ? "Mettre a jour le profil" : "Enregistrer le profil" }), isEdit ? (_jsx(SecondaryButton, { type: "button", onClick: () => onCancel?.(), children: "Annuler" })) : null] })] })] })); };