riseup-squad23/src/pages/ProfilePage.jsx

309 lines
8.3 KiB
JavaScript
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.

import React, { useState, useEffect, useCallback } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import "./style/ProfilePage.css";
const MOCK_API_BASE_URL = "https://mock.apidog.com/m1/1053378-0-default";
const getLocalAvatar = () => localStorage.getItem('user_avatar');
const setLocalAvatar = (avatarData) => localStorage.setItem('user_avatar', avatarData);
const clearLocalAvatar = () => localStorage.removeItem('user_avatar');
const ROLES = {
ADMIN: "Administrador",
SECRETARY: "Secretária",
DOCTOR: "Médico",
FINANCIAL: "Financeiro"
};
const ProfilePage = () => {
const location = useLocation();
const navigate = useNavigate();
const getRoleFromPath = useCallback(() => {
const path = location.pathname;
if (path.includes("/admin")) return ROLES.ADMIN;
if (path.includes("/secretaria")) return ROLES.SECRETARY;
if (path.includes("/medico")) return ROLES.DOCTOR;
if (path.includes("/financeiro")) return ROLES.FINANCIAL;
return "Usuário";
}, [location.pathname]);
const userRole = getRoleFromPath();
const [userName, setUserName] = useState("Admin Padrão");
const [userEmail, setUserEmail] = useState("admin@squad23.com");
const [avatarUrl, setAvatarUrl] = useState(null);
const [isEditingName, setIsEditingName] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const handleEscKey = (event) => {
if (event.keyCode === 27) handleClose();
};
document.addEventListener('keydown', handleEscKey);
return () => document.removeEventListener('keydown', handleEscKey);
}, []);
useEffect(() => {
const loadProfileData = () => {
const localAvatar = getLocalAvatar();
if (localAvatar) {
setAvatarUrl(localAvatar);
}
};
loadProfileData();
}, []);
const handleNameSave = () => {
if (userName.trim() === "") {
setError("Nome não pode estar vazio");
return;
}
setIsEditingName(false);
setError(null);
};
const handleNameKeyDown = (event) => {
if (event.key === "Enter") handleNameSave();
if (event.key === "Escape") {
setUserName("Admin Padrão");
setIsEditingName(false);
setError(null);
}
};
const handleClose = () => navigate(-1);
const handleAvatarUpload = async (event) => {
const file = event.target.files[0];
if (!file) return;
setError(null);
const MAX_FILE_SIZE = 5 * 1024 * 1024;
const ACCEPTED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (file.size > MAX_FILE_SIZE) {
setError("Arquivo muito grande. Máximo 5MB.");
return;
}
if (!ACCEPTED_TYPES.includes(file.type)) {
setError("Tipo de arquivo não suportado. Use JPEG, PNG, GIF ou WebP.");
return;
}
setIsUploading(true);
try {
try {
const result = await uploadAvatarToMockAPI(file);
const newAvatarUrl = result.url || result.avatarUrl;
if (newAvatarUrl) {
setAvatarUrl(newAvatarUrl);
setLocalAvatar(newAvatarUrl);
console.log('Avatar enviado para API com sucesso');
return;
}
} catch (apiError) {
console.log('API não disponível, salvando localmente...');
}
const reader = new FileReader();
reader.onload = (e) => {
const imageDataUrl = e.target.result;
setLocalAvatar(imageDataUrl);
setAvatarUrl(imageDataUrl);
console.log('Avatar salvo localmente');
};
reader.readAsDataURL(file);
} catch (error) {
console.error('Erro no processamento:', error);
const reader = new FileReader();
reader.onload = (e) => {
const imageDataUrl = e.target.result;
setLocalAvatar(imageDataUrl);
setAvatarUrl(imageDataUrl);
};
reader.readAsDataURL(file);
} finally {
setIsUploading(false);
event.target.value = '';
}
};
const uploadAvatarToMockAPI = async (file) => {
const formData = new FormData();
formData.append("avatar", file);
const response = await fetch(`${MOCK_API_BASE_URL}/storage/v1/object/avatars/[path]`, {
method: "POST",
body: formData
});
if (!response.ok) {
return null;
}
return await response.json();
};
const clearAvatar = () => {
fetch(`${MOCK_API_BASE_URL}/storage/v1/object/avatars/[path]`, {
method: "DELETE"
}).catch(() => {
});
clearLocalAvatar();
setAvatarUrl(null);
};
return (
<div className="profile-overlay" role="dialog" aria-modal="true">
<div className="profile-modal">
<button
className="profile-close"
onClick={handleClose}
aria-label="Fechar Perfil"
>
×
</button>
<div className="profile-content">
<div className="profile-left">
<div className="avatar-wrapper">
<div className="avatar-square">
{avatarUrl ? (
<img
src={avatarUrl}
alt="Avatar do usuário"
className="avatar-img"
onError={() => {
setAvatarUrl(null);
clearLocalAvatar();
}}
/>
) : (
<div className="avatar-placeholder">
{userName.split(' ').map(n => n[0]).join('').toUpperCase()}
</div>
)}
</div>
<label
className={`avatar-edit-btn ${isUploading ? 'uploading' : ''}`}
title="Alterar foto de perfil"
>
{isUploading ? 'Enviando...' : 'Alterar Foto'}
<input
type="file"
accept="image/*"
onChange={handleAvatarUpload}
disabled={isUploading}
style={{ display: "none" }}
/>
</label>
{isUploading && (
<p className="upload-status">
Processando imagem...
</p>
)}
</div>
</div>
<div className="profile-right">
<div className="profile-name-row">
{isEditingName ? (
<div className="name-edit-wrapper">
<input
className="profile-name-input"
value={userName}
onChange={(e) => setUserName(e.target.value)}
onBlur={handleNameSave}
onKeyDown={handleNameKeyDown}
autoFocus
maxLength={50}
/>
<div className="name-edit-hint">
Pressione Enter para salvar, ESC para cancelar
</div>
</div>
) : (
<h2 className="profile-username">
{userName}
</h2>
)}
<button
className="profile-edit-inline"
onClick={() => setIsEditingName(!isEditingName)}
type="button"
aria-label={isEditingName ? 'Cancelar edição' : 'Editar nome'}
>
{isEditingName ? 'Cancelar' : 'Editar'}
</button>
</div>
{error && (
<div className="error-message">
{error}
</div>
)}
<div className="profile-info">
<p className="profile-email">
<span>Email:</span>
<strong>{userEmail}</strong>
</p>
<p className="profile-role">
<span>Cargo:</span>
<strong>{userRole}</strong>
</p>
</div>
<div className="profile-actions">
{avatarUrl && (
<button onClick={clearAvatar} className="btn btn-clear">
Remover Avatar
</button>
)}
<button
className="btn btn-close"
onClick={handleClose}
>
Fechar Perfil
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default ProfilePage;