s3 fix
This commit is contained in:
@@ -15,8 +15,9 @@ import {
|
||||
ContactInfo,
|
||||
PhotoUploadModal,
|
||||
} from '@/components/profile';
|
||||
import { agentsService, AgentProfile } from '@/services/agents.service';
|
||||
import { agentsService, AgentProfile, FieldValueResponse } from '@/services/agents.service';
|
||||
import { uploadService } from '@/services/upload.service';
|
||||
import { mapFieldValuesToExperience, ExperienceData } from '@/utils/profileDataMapper';
|
||||
|
||||
// Mock data for sections not yet available from API
|
||||
const mockData = {
|
||||
@@ -73,24 +74,68 @@ const mockData = {
|
||||
],
|
||||
};
|
||||
|
||||
// Default experience data when no field values are available
|
||||
const defaultExperience: ExperienceData = {
|
||||
years: '-',
|
||||
contracts: '-',
|
||||
licensingAreas: [],
|
||||
expertiseYears: [],
|
||||
certifications: [],
|
||||
};
|
||||
|
||||
export default function AgentDashboard() {
|
||||
const { data: session } = useSession();
|
||||
const [agentProfile, setAgentProfile] = useState<AgentProfile | null>(null);
|
||||
const [fieldValues, setFieldValues] = useState<FieldValueResponse[]>([]);
|
||||
const [experienceData, setExperienceData] = useState<ExperienceData>(defaultExperience);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isPhotoModalOpen, setIsPhotoModalOpen] = useState(false);
|
||||
const [imageError, setImageError] = useState(false);
|
||||
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
|
||||
|
||||
const defaultImage = '/assets/demo_images/8f017153a7b4a239a4f0691234ef97dd55092282.jpg';
|
||||
|
||||
// Fetch agent profile on mount
|
||||
// Helper to check if avatar is an S3 key (not a full URL or local path)
|
||||
const isS3Key = (avatar: string | null | undefined): boolean => {
|
||||
if (!avatar) return false;
|
||||
// S3 keys don't start with http or /
|
||||
return !avatar.startsWith('http') && !avatar.startsWith('/');
|
||||
};
|
||||
|
||||
// Fetch agent profile and field values on mount
|
||||
useEffect(() => {
|
||||
const fetchProfile = async () => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const profile = await agentsService.getMyProfile();
|
||||
|
||||
// Fetch profile and field values in parallel
|
||||
const [profile, fieldValuesResponse] = await Promise.all([
|
||||
agentsService.getMyProfile(),
|
||||
agentsService.getFieldValues(),
|
||||
]);
|
||||
|
||||
setAgentProfile(profile);
|
||||
setFieldValues(fieldValuesResponse.fieldValues);
|
||||
|
||||
// Map field values to experience data structure
|
||||
const mappedExperience = mapFieldValuesToExperience(fieldValuesResponse.fieldValues);
|
||||
setExperienceData(mappedExperience);
|
||||
|
||||
// If avatar is an S3 key, fetch presigned URL
|
||||
if (profile.avatar && isS3Key(profile.avatar)) {
|
||||
try {
|
||||
const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar);
|
||||
setAvatarUrl(presignedUrl);
|
||||
} catch (avatarErr) {
|
||||
console.error('Failed to get avatar URL:', avatarErr);
|
||||
// Don't fail the whole page, just use default image
|
||||
}
|
||||
} else if (profile.avatar) {
|
||||
// It's already a full URL or local path
|
||||
setAvatarUrl(profile.avatar);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch profile:', err);
|
||||
setError('Failed to load profile data');
|
||||
@@ -99,17 +144,27 @@ export default function AgentDashboard() {
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfile();
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const handlePhotoUpload = async (file: File) => {
|
||||
// Upload avatar to S3 (uses agent ID as filename for auto-replacement)
|
||||
const uploadedFile = await uploadService.uploadAvatar(file);
|
||||
|
||||
// Update agent profile with the S3 URL
|
||||
// Update agent profile with the S3 key
|
||||
const updatedProfile = await agentsService.updateProfile({ avatar: uploadedFile.url });
|
||||
setImageError(false); // Reset error state for new image
|
||||
setAgentProfile(updatedProfile);
|
||||
|
||||
// Fetch new presigned URL for the uploaded avatar
|
||||
if (uploadedFile.url && isS3Key(uploadedFile.url)) {
|
||||
try {
|
||||
const presignedUrl = await uploadService.getPresignedDownloadUrl(uploadedFile.url);
|
||||
setAvatarUrl(presignedUrl);
|
||||
} catch (err) {
|
||||
console.error('Failed to get presigned URL for new avatar:', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getProfileImageUrl = () => {
|
||||
@@ -118,18 +173,23 @@ export default function AgentDashboard() {
|
||||
return defaultImage;
|
||||
}
|
||||
|
||||
// If we have a presigned URL from S3, use it
|
||||
if (avatarUrl) {
|
||||
return avatarUrl;
|
||||
}
|
||||
|
||||
// Check for null, undefined, or empty string
|
||||
if (!agentProfile?.avatar || agentProfile.avatar.trim() === '') {
|
||||
return defaultImage;
|
||||
}
|
||||
|
||||
// S3 URLs are full URLs starting with http
|
||||
if (agentProfile.avatar.startsWith('http')) {
|
||||
// For relative paths (local assets), return as-is
|
||||
if (agentProfile.avatar.startsWith('/')) {
|
||||
return agentProfile.avatar;
|
||||
}
|
||||
|
||||
// For relative paths (local assets), return as-is
|
||||
return agentProfile.avatar;
|
||||
// Default fallback
|
||||
return defaultImage;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
@@ -240,8 +300,8 @@ export default function AgentDashboard() {
|
||||
requestsHref="/agent/network"
|
||||
/>
|
||||
|
||||
{/* Experience Section */}
|
||||
<ExperienceSection experience={mockData.experience} />
|
||||
{/* Experience Section - Dynamic data from profile fields */}
|
||||
<ExperienceSection experience={experienceData} />
|
||||
|
||||
{/* Info Cards Section */}
|
||||
<div className="flex flex-col lg:grid lg:grid-cols-3 gap-6">
|
||||
@@ -306,6 +366,7 @@ export default function AgentDashboard() {
|
||||
onClose={() => setIsPhotoModalOpen(false)}
|
||||
onUpload={handlePhotoUpload}
|
||||
currentPhoto={agentProfile.avatar}
|
||||
currentPhotoUrl={avatarUrl}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user