This commit is contained in:
pradeepkumar
2026-01-24 23:10:02 +05:30
parent b940e77a67
commit 39af9bc59d
8 changed files with 496 additions and 103 deletions

View File

@@ -1,5 +1,6 @@
'use client';
import { useState } from 'react';
import { Tag } from './Tag';
interface ExperienceData {
@@ -14,7 +15,25 @@ interface ExperienceSectionProps {
experience: ExperienceData;
}
const INITIAL_DISPLAY_COUNT = 6;
const EXPERTISE_INITIAL_COUNT = 4;
export function ExperienceSection({ experience }: ExperienceSectionProps) {
const [showAllLicensing, setShowAllLicensing] = useState(false);
const [showAllExpertise, setShowAllExpertise] = useState(false);
// Calculate how many more items are hidden
const licensingRemaining = experience.licensingAreas.length - INITIAL_DISPLAY_COUNT;
const expertiseRemaining = experience.expertiseYears.length - EXPERTISE_INITIAL_COUNT;
// Get displayed items
const displayedLicensing = showAllLicensing
? experience.licensingAreas
: experience.licensingAreas.slice(0, INITIAL_DISPLAY_COUNT);
const displayedExpertise = showAllExpertise
? experience.expertiseYears
: experience.expertiseYears.slice(0, EXPERTISE_INITIAL_COUNT);
return (
<div className="bg-white rounded-[20px] p-4 lg:p-5">
<h2 className="text-[20px] font-bold text-[#00293D] font-fractul leading-[24px] mb-4 text-center lg:text-left">Experience</h2>
@@ -24,26 +43,51 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) {
<div>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-2">Years in Experience</p>
<ul className="list-disc list-inside">
<li className="font-serif font-medium text-[15px] leading-[21px] text-[#00293D]">{experience.years}</li>
<li className="font-serif font-medium text-[15px] leading-[21px] text-[#00293D]">
{experience.years !== '-' ? experience.years : <span className="text-[#00293D]/40">Not specified</span>}
</li>
</ul>
</div>
{/* Horizontal divider */}
<div className="w-full h-0 border-t-[0.5px] border-solid border-[#00293D]/20" />
<div>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-2">Number of contract closed</p>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-2">Number of contracts closed</p>
<ul className="list-disc list-inside">
<li className="font-serif font-medium text-[15px] leading-[21px] text-[#00293D]">{experience.contracts}</li>
<li className="font-serif font-medium text-[15px] leading-[21px] text-[#00293D]">
{experience.contracts !== '-' ? experience.contracts : <span className="text-[#00293D]/40">Not specified</span>}
</li>
</ul>
</div>
<div>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-3">Licensing &amp; Areas</p>
<div className="flex flex-wrap gap-2">
{experience.licensingAreas.map((area, idx) => (
<Tag key={idx} variant="light">
{area}
</Tag>
))}
<span className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer">+3 More</span>
{experience.licensingAreas.length > 0 ? (
<>
{displayedLicensing.map((area, idx) => (
<Tag key={idx} variant="light">
{area}
</Tag>
))}
{!showAllLicensing && licensingRemaining > 0 && (
<button
onClick={() => setShowAllLicensing(true)}
className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer hover:bg-gray-50 transition-colors"
>
+{licensingRemaining} More
</button>
)}
{showAllLicensing && experience.licensingAreas.length > INITIAL_DISPLAY_COUNT && (
<button
onClick={() => setShowAllLicensing(false)}
className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer hover:bg-gray-50 transition-colors"
>
Show Less
</button>
)}
</>
) : (
<span className="text-[14px] font-serif text-[#00293D]/40">No licensed areas added</span>
)}
</div>
</div>
</div>
@@ -57,24 +101,51 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) {
<div>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-3">Areas in expertise &amp; Years</p>
<div className="flex flex-wrap gap-2">
{experience.expertiseYears.slice(0, 4).map((item, idx) => (
<Tag key={idx} variant="light">
{item.area} {item.years}
</Tag>
))}
<span className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer">+3 More</span>
{experience.expertiseYears.length > 0 ? (
<>
{displayedExpertise.map((item, idx) => (
<Tag key={idx} variant="light">
{item.years ? `${item.area} ${item.years}` : item.area}
</Tag>
))}
{!showAllExpertise && expertiseRemaining > 0 && (
<button
onClick={() => setShowAllExpertise(true)}
className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer hover:bg-gray-50 transition-colors"
>
+{expertiseRemaining} More
</button>
)}
{showAllExpertise && experience.expertiseYears.length > EXPERTISE_INITIAL_COUNT && (
<button
onClick={() => setShowAllExpertise(false)}
className="inline-flex items-center justify-center h-[28px] px-3 rounded-[15px] border border-[#00293d]/10 text-[15px] font-light font-serif text-[#00293d] cursor-pointer hover:bg-gray-50 transition-colors"
>
Show Less
</button>
)}
</>
) : (
<span className="text-[14px] font-serif text-[#00293D]/40">No expertise areas added</span>
)}
</div>
</div>
<div>
<p className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] mb-3">Certifications</p>
<ul className="space-y-3">
{experience.certifications.map((cert, idx) => (
<li key={idx}>
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">{cert.name}</span>
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] opacity-50 ml-3">{cert.org}</p>
</li>
))}
</ul>
{experience.certifications.length > 0 ? (
<ul className="space-y-3">
{experience.certifications.map((cert, idx) => (
<li key={idx}>
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">{cert.name}</span>
{cert.org && (
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] opacity-50 ml-3">{cert.org}</p>
)}
</li>
))}
</ul>
) : (
<span className="text-[14px] font-serif text-[#00293D]/40">No certifications added</span>
)}
</div>
</div>
</div>

View File

@@ -8,9 +8,10 @@ interface PhotoUploadModalProps {
onClose: () => void;
onUpload: (file: File) => Promise<void>;
currentPhoto?: string | null;
currentPhotoUrl?: string | null; // Presigned URL for display
}
export function PhotoUploadModal({ isOpen, onClose, onUpload, currentPhoto }: PhotoUploadModalProps) {
export function PhotoUploadModal({ isOpen, onClose, onUpload, currentPhoto, currentPhotoUrl }: PhotoUploadModalProps) {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [isDragging, setIsDragging] = useState(false);
@@ -170,20 +171,14 @@ export function PhotoUploadModal({ isOpen, onClose, onUpload, currentPhoto }: Ph
}`}
>
{/* Current Photo Preview */}
{currentPhoto && (
{(currentPhotoUrl || currentPhoto) && (
<div className="flex justify-center mb-4">
<div className="relative w-[100px] h-[100px] rounded-[10px] overflow-hidden opacity-50">
<Image
src={
currentPhoto.startsWith('http')
? currentPhoto
: currentPhoto.startsWith('/uploads')
? `${process.env.NEXT_PUBLIC_API_URL?.replace('/api/v1', '')}${currentPhoto}`
: currentPhoto
}
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={currentPhotoUrl || currentPhoto || ''}
alt="Current photo"
fill
className="object-cover"
className="w-full h-full object-cover"
/>
</div>
</div>