Function bodies 182 total
TenderCardSkeleton function · typescript · L129-L152 (24 LOC)app/services/global-tenders-hub/page.tsx
function TenderCardSkeleton() {
return (
<div className="rounded-2xl p-6 theme-panel animate-pulse">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-gray-200 dark:bg-white/10" />
<div>
<div className="h-4 bg-gray-200 dark:bg-white/10 rounded w-32 mb-2" />
<div className="h-3 bg-gray-200 dark:bg-white/10 rounded w-20" />
</div>
</div>
<div className="h-5 bg-gray-200 dark:bg-white/10 rounded-full w-16" />
</div>
<div className="h-4 bg-gray-200 dark:bg-white/10 rounded w-full mb-2" />
<div className="h-4 bg-gray-200 dark:bg-white/10 rounded w-3/4 mb-4" />
<div className="h-3 bg-gray-200 dark:bg-white/10 rounded w-full mb-2" />
<div className="h-3 bg-gray-200 dark:bg-white/10 rounded w-2/3 mb-4" />
<div className="flex items-center justify-between pt-4 border-t border-gray-100 TenderCard function · typescript · L155-L245 (91 LOC)app/services/global-tenders-hub/page.tsx
function TenderCard({ tender, locale, onView, onSave, isSaved }: {
tender: Tender
locale: string
onView: (t: Tender) => void
onSave: (id: string) => void
isSaved: boolean
}) {
const isRtl = locale === 'ar'
const title = isRtl ? tender.titleAr : tender.title
const desc = isRtl ? tender.descriptionAr : tender.description
const org = isRtl ? tender.issuingOrganizationAr : tender.issuingOrganization
const sector = isRtl ? (sectorsAr[tender.sector] || tender.sector) : tender.sector
const country = isRtl ? tender.countryAr : tender.country
const flag = countryFlags[tender.country] || ''
const days = daysUntil(tender.deadline)
const isUrgent = tender.status === 'Closing Soon'
const isClosed = tender.status === 'Closed'
return (
<div className={`rounded-2xl p-6 theme-panel hover:shadow-lg transition-all group ${isClosed ? 'opacity-70' : ''}`}>
{/* Header: Org + Status */}
<div className="flex items-start justify-between gap-3 mb-3">
<divTenderDetailModal function · typescript · L248-L451 (204 LOC)app/services/global-tenders-hub/page.tsx
function TenderDetailModal({ tender, locale, onClose, onSave, isSaved, relatedTenders, onViewRelated }: {
tender: Tender
locale: string
onClose: () => void
onSave: (id: string) => void
isSaved: boolean
relatedTenders: Tender[]
onViewRelated: (t: Tender) => void
}) {
const isRtl = locale === 'ar'
const title = isRtl ? tender.titleAr : tender.title
const desc = isRtl ? tender.descriptionAr : tender.description
const org = isRtl ? tender.issuingOrganizationAr : tender.issuingOrganization
const sector = isRtl ? (sectorsAr[tender.sector] || tender.sector) : tender.sector
const region = isRtl ? (regionsAr[tender.region] || tender.region) : tender.region
const country = isRtl ? tender.countryAr : tender.country
const tenderType = isRtl ? (tenderTypesAr[tender.tenderType] || tender.tenderType) : tender.tenderType
const requirements = isRtl ? tender.requirementsAr : tender.requirements
const submissionMethod = isRtl ? tender.submissionMethodAr : tender.submissiMultiSelect function · typescript · L454-L521 (68 LOC)app/services/global-tenders-hub/page.tsx
function MultiSelect({ label, options, selected, onChange, locale }: {
label: string
options: string[]
selected: string[]
onChange: (v: string[]) => void
locale: string
}) {
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const isRtl = locale === 'ar'
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)
}
document.addEventListener('mousedown', handleClick)
return () => document.removeEventListener('mousedown', handleClick)
}, [])
const toggle = (val: string) => {
onChange(selected.includes(val) ? selected.filter(v => v !== val) : [...selected, val])
}
return (
<div ref={ref} className="relative">
<label className="block text-sm font-medium mb-1.5" style={{ color: 'var(--text-secondary)' }}>{label}</label>
<button
onClick={() => setOpen(!open)}
className="w-full flex items-center justify-bESGApplicationPage function · typescript · L5-L7 (3 LOC)app/services/[id]/apply/page.tsx
export default function ESGApplicationPage() {
return <ESGAccordionForm />
}MapSkeleton function · typescript · L42-L51 (10 LOC)app/services/market-directory/page.tsx
function MapSkeleton() {
return (
<div className="w-full h-full rounded-xl flex items-center justify-center" style={{ background: 'var(--panel-2)', minHeight: 400 }}>
<div className="text-center">
<div className="w-10 h-10 border-2 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-3" />
<span style={{ color: 'var(--muted)', fontSize: 13 }}>Loading map...</span>
</div>
</div>
)
}MemberAccessGuard function · typescript · L60-L78 (19 LOC)app/services/market-directory/page.tsx
function MemberAccessGuard({ md, isRtl }: { md: MD; isRtl: boolean }) {
return (
<div className="min-h-screen flex items-center justify-center px-4" style={{ background: 'var(--bg)' }}>
<div className="max-w-md w-full text-center">
<div className="w-20 h-20 rounded-full bg-amber-100 dark:bg-amber-500/20 flex items-center justify-center mx-auto mb-6">
<svg className="w-10 h-10 text-amber-600 dark:text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h2 className="text-2xl font-bold mb-2" style={{ color: 'var(--text)' }}>{md.memberOnly}</h2>
<p className="mb-8" style={{ color: 'var(--muted)' }}>{md.memberOnlyDesc}</p>
<div className={`flex flex-col sm:flex-row gap-3 justify-center ${isRtl ? 'sm:flex-Open data scored by Repobility · https://repobility.com
SectorBadge function · typescript · L82-L86 (5 LOC)app/services/market-directory/page.tsx
function SectorBadge({ sector, isRtl }: { sector: string; isRtl: boolean }) {
const colors = sectorColors[sector] || { bg: 'bg-gray-100 dark:bg-white/10', text: 'text-gray-800 dark:text-gray-300', border: 'border-gray-200 dark:border-white/10' }
const label = isRtl ? (sectorsAr[sector] || sector) : sector
return <span className={`inline-flex px-2 py-0.5 rounded-full text-xs font-medium border ${colors.bg} ${colors.text} ${colors.border}`}>{label}</span>
}AreaBadge function · typescript · L88-L96 (9 LOC)app/services/market-directory/page.tsx
function AreaBadge({ area, isRtl }: { area: string; isRtl: boolean }) {
const label = isRtl ? (areasAr[area] || area) : area
return (
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border bg-emerald-50 dark:bg-emerald-500/10 text-emerald-700 dark:text-emerald-300 border-emerald-200 dark:border-emerald-500/20">
<svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
{label}
</span>
)
}StatusBadge function · typescript · L98-L107 (10 LOC)app/services/market-directory/page.tsx
function StatusBadge({ status, isRtl }: { status: string; isRtl: boolean }) {
const isActive = status === 'Active'
const label = isRtl ? (statusesAr[status] || status) : status
return (
<span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border ${isActive ? 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-300 border-green-200 dark:border-green-500/20' : 'bg-gray-100 dark:bg-white/10 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-white/10'}`}>
<span className={`w-1.5 h-1.5 rounded-full ${isActive ? 'bg-green-500' : 'bg-gray-400'}`} />
{label}
</span>
)
}SaturationBadge function · typescript · L109-L112 (4 LOC)app/services/market-directory/page.tsx
function SaturationBadge({ level }: { level: string }) {
const c = saturationColors[level] || ''
return <span className={`inline-flex px-2 py-0.5 rounded-full text-xs font-medium border ${c}`}>{level}</span>
}GrowthBadge function · typescript · L114-L117 (4 LOC)app/services/market-directory/page.tsx
function GrowthBadge({ trend }: { trend: string }) {
const c = growthColors[trend] || ''
return <span className={`inline-flex px-2 py-0.5 rounded-full text-xs font-medium border ${c}`}>{trend}</span>
}CompanyAvatar function · typescript · L119-L127 (9 LOC)app/services/market-directory/page.tsx
function CompanyAvatar({ company }: { company: Company }) {
const color = sectorHexColors[company.sector] || '#6b7280'
const initials = company.name.split(' ').map((w) => w[0]).join('').slice(0, 2).toUpperCase()
return (
<div className="w-10 h-10 rounded-lg flex items-center justify-center text-white text-sm font-bold shrink-0" style={{ background: color }}>
{initials}
</div>
)
}CardSkeleton function · typescript · L131-L143 (13 LOC)app/services/market-directory/page.tsx
function CardSkeleton() {
return (
<div className="theme-panel rounded-xl p-4 animate-pulse">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg" style={{ background: 'var(--panel-2)' }} />
<div className="flex-1">
<div className="h-4 rounded w-3/4 mb-2" style={{ background: 'var(--panel-2)' }} />
<div className="h-3 rounded w-1/2" style={{ background: 'var(--panel-2)' }} />
</div>
</div>
</div>
)
}CompanyCard function · typescript · L287-L320 (34 LOC)app/services/market-directory/page.tsx
function CompanyCard({ company, isRtl, isSelected, onClick }: { company: Company; isRtl: boolean; isSelected: boolean; onClick: () => void }) {
return (
<button
onClick={onClick}
className={`w-full text-left rounded-xl p-3 transition-all ${isSelected ? 'ring-2 ring-blue-500' : ''}`}
style={{ background: isSelected ? 'var(--panel-2)' : 'var(--panel)', border: '1px solid var(--border)' }}
>
<div className={`flex items-start gap-3 ${isRtl ? 'flex-row-reverse text-right' : ''}`}>
<CompanyAvatar company={company} />
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-sm font-semibold truncate" style={{ color: 'var(--text)' }}>
{isRtl ? company.nameAr : company.name}
</span>
{company.isGoldenVendor && (
<span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded-full text-[10px] font-semibold bg-amber-10Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
GlobalSearchDropdown function · typescript · L473-L529 (57 LOC)app/services/market-directory/page.tsx
function GlobalSearchDropdown({
query, isRtl, md, onSelectCompany, onSelectSector, onSelectArea,
}: {
query: string; isRtl: boolean; md: MD
onSelectCompany: (c: Company) => void
onSelectSector: (s: string) => void
onSelectArea: (a: string) => void
}) {
const q = query.toLowerCase()
const matchedCompanies = allCompanies.filter((c) => c.name.toLowerCase().includes(q) || c.nameAr.includes(query)).slice(0, 5)
const matchedAreas = areas.filter((a) => a.toLowerCase().includes(q) || (areasAr[a] || '').includes(query)).slice(0, 3)
const matchedSectors = sectors.filter((s) => s.toLowerCase().includes(q) || (sectorsAr[s] || '').includes(query)).slice(0, 3)
if (!matchedCompanies.length && !matchedAreas.length && !matchedSectors.length) {
return (
<div className="absolute top-full mt-1 w-full rounded-xl overflow-hidden z-50 shadow-lg" style={{ background: 'var(--panel)', border: '1px solid var(--border)' }}>
<div className="p-4 text-center text-sm" style={{ cSetupAdvisorForm function · typescript · L615-L730 (116 LOC)app/services/market-directory/page.tsx
function SetupAdvisorForm({
md, isRtl, onSubmit,
}: {
md: MD; isRtl: boolean; onSubmit: (data: AdvisorFormData) => void
}) {
const [form, setForm] = useState<AdvisorFormData>({
sector: '', subSector: '', companySize: '', legalStructure: '',
budget: '', priorities: [], additionalContext: '',
})
const togglePriority = (p: string) => {
setForm((prev) => ({
...prev,
priorities: prev.priorities.includes(p) ? prev.priorities.filter((x) => x !== p) : [...prev.priorities, p],
}))
}
const canSubmit = form.sector && form.companySize
return (
<div className="max-w-2xl mx-auto">
<div className="theme-panel rounded-2xl p-6 sm:p-8">
<div className="space-y-5">
{/* Sector */}
<div>
<label className="block text-sm font-medium mb-1.5" style={{ color: 'var(--text)' }}>{md.advisorForm.sector} *</label>
<select value={form.sector} onChange={(e) => setForm({ ...form, sector: e.target.value })} classSetupAdvisorLoading function · typescript · L734-L756 (23 LOC)app/services/market-directory/page.tsx
function SetupAdvisorLoading({ md }: { md: MD }) {
const [step, setStep] = useState(0)
const steps = [md.advisorLoading.step1, md.advisorLoading.step2, md.advisorLoading.step3, md.advisorLoading.step4]
useEffect(() => {
const interval = setInterval(() => setStep((s) => Math.min(s + 1, steps.length - 1)), 600)
return () => clearInterval(interval)
}, [steps.length])
return (
<div className="max-w-lg mx-auto text-center py-16">
<div className="w-16 h-16 border-3 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-6" />
<h3 className="text-lg font-bold mb-4" style={{ color: 'var(--text)' }}>{md.advisorLoading.title}</h3>
<div className="space-y-2">
{steps.map((s, i) => (
<div key={i} className={`text-sm transition-opacity duration-300 ${i <= step ? 'opacity-100' : 'opacity-30'}`} style={{ color: i <= step ? 'var(--text)' : 'var(--muted)' }}>
{i <= step ? '\u2713' : '\u25CB'} {s}
</div>
MarketDirectoryPage function · typescript · L913-L1249 (337 LOC)app/services/market-directory/page.tsx
export default function MarketDirectoryPage() {
const { locale, t, dir } = useI18n()
const md = t.marketDirectory
const isRtl = dir === 'rtl'
const router = useRouter()
const searchParams = useSearchParams()
// ─── Auth mock ──────────────────────────────────────────────────────────────
const [isMember, setIsMember] = useState(false)
const [loading, setLoading] = useState(true)
useEffect(() => {
const timer = setTimeout(() => { setIsMember(true); setLoading(false) }, 400)
return () => clearTimeout(timer)
}, [])
// ─── URL-synced state ───────────────────────────────────────────────────────
const mode = (searchParams.get('mode') as 'explore' | 'advisor') || 'explore'
const sectorFilter = searchParams.get('sector') || ''
const areaFilter = searchParams.get('area') || ''
const employeeFilter = searchParams.get('employees') || ''
const legalFilter = searchParams.get('legal') || ''
const activeOnly = searchParams.get('active') === '1'
const golServicesPage function · typescript · L25-L295 (271 LOC)app/services/page.tsx
export default function ServicesPage() {
const { locale } = useI18n()
const router = useRouter()
const [services, setServices] = useState<Service[]>([])
const [filters, setFilters] = useState<FiltersData>({ departments: [], platforms: [] })
const [loading, setLoading] = useState(true)
const [searchQuery, setSearchQuery] = useState('')
const [selectedPlatform, setSelectedPlatform] = useState('')
const [selectedDepartment, setSelectedDepartment] = useState('')
useEffect(() => {
fetchServices()
}, [selectedPlatform, selectedDepartment, searchQuery])
const fetchServices = async () => {
setLoading(true)
try {
const params = new URLSearchParams()
if (selectedPlatform) params.set('platform', selectedPlatform)
if (selectedDepartment) params.set('department', selectedDepartment)
if (searchQuery) params.set('search', searchQuery)
const response = await fetch(`/api/services?${params.toString()}`)
const data = await response.MemberAccessGuard function · typescript · L32-L54 (23 LOC)app/services/procurement-hub/page.tsx
function MemberAccessGuard({ ph, isRtl }: { ph: PH; isRtl: boolean }) {
return (
<div className="min-h-screen flex items-center justify-center px-4" style={{ background: 'var(--bg)' }}>
<div className="max-w-md w-full text-center">
<div className="w-20 h-20 rounded-full bg-amber-100 dark:bg-amber-500/20 flex items-center justify-center mx-auto mb-6">
<svg className="w-10 h-10 text-amber-600 dark:text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h2 className="text-2xl font-bold mb-2" style={{ color: 'var(--text)' }}>{ph.memberOnly}</h2>
<p className="mb-8" style={{ color: 'var(--muted)' }}>{ph.memberOnlyDesc}</p>
<div className={`flex flex-col sm:flex-row gap-3 justify-center ${isRtl ? 'sm:flex-SectorBadge function · typescript · L58-L66 (9 LOC)app/services/procurement-hub/page.tsx
function SectorBadge({ sector, isRtl }: { sector: string; isRtl: boolean }) {
const colors = sectorColors[sector] || { bg: 'bg-gray-100 dark:bg-white/10', text: 'text-gray-800 dark:text-gray-300', border: 'border-gray-200 dark:border-white/10' }
const label = isRtl ? (sectorsAr[sector] || sector) : sector
return (
<span className={`px-2.5 py-0.5 rounded-full text-xs font-medium border ${colors.bg} ${colors.text} ${colors.border}`}>
{label}
</span>
)
}TierBadge function · typescript · L70-L78 (9 LOC)app/services/procurement-hub/page.tsx
function TierBadge({ tier, isRtl }: { tier: string; isRtl: boolean }) {
const colors = tierColors[tier] || ''
const label = isRtl ? (memberTiersAr[tier] || tier) : tier
return (
<span className={`px-2.5 py-0.5 rounded-full text-xs font-medium border ${colors}`}>
{label}
</span>
)
}Repobility · open methodology · https://repobility.com/research/
StatusBadge function · typescript · L82-L90 (9 LOC)app/services/procurement-hub/page.tsx
function StatusBadge({ status, isRtl }: { status: string; isRtl: boolean }) {
const colors = statusColors[status] || ''
const label = isRtl ? (statusesAr[status] || status) : status
return (
<span className={`px-2.5 py-0.5 rounded-full text-xs font-medium border ${colors}`}>
{label}
</span>
)
}GoldenVendorBadge function · typescript · L94-L103 (10 LOC)app/services/procurement-hub/page.tsx
function GoldenVendorBadge({ label }: { label: string }) {
return (
<span className="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-500/30">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
{label}
</span>
)
}CompanyAvatar function · typescript · L107-L116 (10 LOC)app/services/procurement-hub/page.tsx
function CompanyAvatar({ name, size = 'md' }: { name: string; size?: 'sm' | 'md' | 'lg' }) {
const colors = companyColors[name] || { bg: 'bg-gray-500', text: 'text-white' }
const initials = name.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()
const sizeClasses = size === 'sm' ? 'w-8 h-8 text-xs' : size === 'lg' ? 'w-14 h-14 text-lg' : 'w-10 h-10 text-sm'
return (
<div className={`${sizeClasses} ${colors.bg} ${colors.text} rounded-xl flex items-center justify-center font-bold flex-shrink-0`}>
{initials}
</div>
)
}StarRating function · typescript · L120-L134 (15 LOC)app/services/procurement-hub/page.tsx
function StarRating({ rating, reviewCount, reviewsLabel }: { rating: number; reviewCount: number; reviewsLabel: string }) {
return (
<div className="flex items-center gap-1.5">
<div className="flex items-center">
{[1, 2, 3, 4, 5].map(star => (
<svg key={star} className={`w-3.5 h-3.5 ${star <= Math.round(rating) ? 'text-amber-400' : 'text-gray-300 dark:text-gray-600'}`} fill="currentColor" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
))}
</div>
<span className="text-xs font-medium" style={{ color: 'var(--text)' }}>{rating.toFixed(1)}</span>
<span className="text-xs" style={{ CardSkeleton function · typescript · L138-L156 (19 LOC)app/services/procurement-hub/page.tsx
function CardSkeleton() {
return (
<div className="rounded-2xl p-6 theme-panel animate-pulse">
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 rounded-xl bg-gray-200 dark:bg-white/10" />
<div className="flex-1">
<div className="h-4 w-32 rounded bg-gray-200 dark:bg-white/10 mb-2" />
<div className="h-3 w-20 rounded bg-gray-200 dark:bg-white/10" />
</div>
</div>
<div className="h-3 w-full rounded bg-gray-200 dark:bg-white/10 mb-2" />
<div className="h-3 w-3/4 rounded bg-gray-200 dark:bg-white/10 mb-4" />
<div className="flex gap-2">
<div className="h-6 w-16 rounded-full bg-gray-200 dark:bg-white/10" />
<div className="h-6 w-16 rounded-full bg-gray-200 dark:bg-white/10" />
</div>
</div>
)
}QuoteRequestForm function · typescript · L588-L698 (111 LOC)app/services/procurement-hub/page.tsx
function QuoteRequestForm({
supplier, isRtl, ph, onClose,
}: {
supplier: Supplier; isRtl: boolean; ph: PH; onClose: () => void
}) {
const qf = ph.quoteForm
const [form, setForm] = useState({ companyName: '', serviceNeeded: '', projectDescription: '', budget: '', timeline: '' })
const [submitted, setSubmitted] = useState(false)
useEffect(() => {
const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }
document.addEventListener('keydown', handler)
document.body.style.overflow = 'hidden'
return () => { document.removeEventListener('keydown', handler); document.body.style.overflow = '' }
}, [onClose])
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
console.log('Quote request submitted:', { supplier: supplier.companyName, ...form })
setSubmitted(true)
setTimeout(onClose, 2000)
}
return (
<div className="fixed inset-0 z-[60] flex items-start justify-center overflow-y-auto" onClick={onClose}>
PostRequirementForm function · typescript · L702-L834 (133 LOC)app/services/procurement-hub/page.tsx
function PostRequirementForm({ isRtl, ph, onClose }: { isRtl: boolean; ph: PH; onClose: () => void }) {
const pf = ph.postForm
const [form, setForm] = useState({ title: '', sector: '', description: '', budget: '', deadline: '', isUrgent: false })
const [reqs, setReqs] = useState<string[]>([])
const [reqInput, setReqInput] = useState('')
const [submitted, setSubmitted] = useState(false)
useEffect(() => {
const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }
document.addEventListener('keydown', handler)
document.body.style.overflow = 'hidden'
return () => { document.removeEventListener('keydown', handler); document.body.style.overflow = '' }
}, [onClose])
const addReq = () => {
if (reqInput.trim()) { setReqs(r => [...r, reqInput.trim()]); setReqInput('') }
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
console.log('Requirement posted:', { ...form, requirements: reqs })
setSubmitted(true)
SubmitProposalForm function · typescript · L838-L936 (99 LOC)app/services/procurement-hub/page.tsx
function SubmitProposalForm({
request, isRtl, ph, onClose,
}: {
request: ProcurementRequest; isRtl: boolean; ph: PH; onClose: () => void
}) {
const prf = ph.proposalForm
const [form, setForm] = useState({ companyName: '', proposalSummary: '', proposedBudget: '', deliveryTimeline: '' })
const [submitted, setSubmitted] = useState(false)
useEffect(() => {
const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }
document.addEventListener('keydown', handler)
document.body.style.overflow = 'hidden'
return () => { document.removeEventListener('keydown', handler); document.body.style.overflow = '' }
}, [onClose])
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
console.log('Proposal submitted:', { request: request.title, ...form })
setSubmitted(true)
setTimeout(onClose, 2000)
}
return (
<div className="fixed inset-0 z-[60] flex items-start justify-center overflow-y-auto" onClick={onClose}>
<divMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
fetchApplication function · typescript · L72-L84 (13 LOC)app/staff/[id]/page.tsx
async function fetchApplication() {
try {
const res = await fetch(`/api/applications/${params.id}`)
const data = await res.json()
if (data.success) {
setApplication(data.application)
}
} catch (error) {
console.error('Error fetching application:', error)
} finally {
setLoading(false)
}
}runAiSummary function · typescript · L86-L109 (24 LOC)app/staff/[id]/page.tsx
async function runAiSummary() {
if (!application) return
setAiSummaryLoading(true)
try {
const res = await fetch('/api/ai/summary', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
description: application.description,
sector: application.sector,
organizationName: application.organizationName,
applicantName: application.applicantName,
}),
})
const data = await res.json()
if (data.success) {
setAiSummary(data.summary)
}
} catch (error) {
console.error('AI summary error:', error)
} finally {
setAiSummaryLoading(false)
}
}generateAiComment function · typescript · L111-L135 (25 LOC)app/staff/[id]/page.tsx
async function generateAiComment(type: string) {
if (!application) return
setAiCommentLoading(true)
try {
const res = await fetch('/api/ai/comment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
description: application.description,
sector: application.sector,
organizationName: application.organizationName,
type,
}),
})
const data = await res.json()
if (data.success) {
setAiComment(data.comment)
setNewNote(data.comment)
}
} catch (error) {
console.error('AI comment error:', error)
} finally {
setAiCommentLoading(false)
}
}runReviewerAssist function · typescript · L137-L166 (30 LOC)app/staff/[id]/page.tsx
async function runReviewerAssist() {
if (!application) return
setReviewerAssistLoading(true)
try {
const res = await fetch('/api/ai/reviewer-assist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
applicationId: application.id,
locale: 'en', // Could be dynamic based on user preference
}),
})
const data = await res.json()
if (data.success) {
setReviewerAssist({
overallAssessment: data.overallAssessment,
recommendedDecision: data.recommendedDecision,
confidenceLevel: data.confidenceLevel,
redFlags: data.redFlags,
strengths: data.strengths,
extraDocumentsSuggested: data.extraDocumentsSuggested,
detailedNotes: data.detailedNotes,
})
}
} catch (error) {
console.error('Reviewer assist error:', error)
} finally {
setReviewerAssistLoading(false)
}
saveNote function · typescript · L168-L185 (18 LOC)app/staff/[id]/page.tsx
async function saveNote() {
if (!newNote.trim()) return
setSavingNote(true)
try {
await fetch(`/api/applications/${params.id}/notes`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ note: newNote }),
})
setNewNote('')
setAiComment(null)
fetchApplication()
} catch (error) {
console.error('Save note error:', error)
} finally {
setSavingNote(false)
}
}updateStatus function · typescript · L187-L216 (30 LOC)app/staff/[id]/page.tsx
async function updateStatus(status: string, note?: string) {
const confirmMessages: Record<string, string> = {
APPROVED: t.staff.detail.confirmApprove,
REJECTED: t.staff.detail.confirmReject,
CORRECTIONS_REQUESTED: t.staff.detail.confirmCorrections,
}
if (!confirm(confirmMessages[status])) return
setActionLoading(status)
try {
const res = await fetch(`/api/applications/${params.id}/status`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status, note: newNote || note }),
})
const data = await res.json()
if (data.success) {
setNewNote('')
fetchApplication()
if (status === 'APPROVED' && data.certificateNumber) {
alert(`Certificate issued: ${data.certificateNumber}`)
}
}
} catch (error) {
console.error('Update status error:', error)
} finally {
setActionLoading(null)
}
}relativeTime function · typescript · L154-L167 (14 LOC)app/staff/page.tsx
function relativeTime(dateStr: string, isRtl: boolean): string {
const now = new Date()
const date = new Date(dateStr)
const diffMs = now.getTime() - date.getTime()
const diffMin = Math.floor(diffMs / 60000)
const diffHr = Math.floor(diffMin / 60)
const diffDay = Math.floor(diffHr / 24)
if (diffMin < 1) return isRtl ? 'الآن' : 'Just now'
if (diffMin < 60) return isRtl ? `منذ ${diffMin} دقيقة` : `${diffMin}m ago`
if (diffHr < 24) return isRtl ? `منذ ${diffHr} ساعة` : `${diffHr}h ago`
if (diffDay < 7) return isRtl ? `منذ ${diffDay} يوم` : `${diffDay}d ago`
return date.toLocaleDateString(isRtl ? 'ar-AE' : 'en-US', { month: 'short', day: 'numeric' })
}StatSkeleton function · typescript · L171-L179 (9 LOC)app/staff/page.tsx
function StatSkeleton() {
return (
<div className="rounded-2xl p-6 theme-panel animate-pulse">
<div className="h-3 w-24 rounded mb-3" style={{ background: 'var(--panel-2)' }} />
<div className="h-8 w-16 rounded mb-2" style={{ background: 'var(--panel-2)' }} />
<div className="h-3 w-20 rounded" style={{ background: 'var(--panel-2)' }} />
</div>
)
}Open data scored by Repobility · https://repobility.com
ServiceCardSkeleton function · typescript · L181-L195 (15 LOC)app/staff/page.tsx
function ServiceCardSkeleton() {
return (
<div className="rounded-2xl p-6 theme-panel animate-pulse">
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 rounded-xl" style={{ background: 'var(--panel-2)' }} />
<div className="flex-1">
<div className="h-4 w-32 rounded mb-2" style={{ background: 'var(--panel-2)' }} />
<div className="h-3 w-20 rounded" style={{ background: 'var(--panel-2)' }} />
</div>
</div>
<div className="h-3 w-full rounded mb-4" style={{ background: 'var(--panel-2)' }} />
<div className="h-8 w-full rounded-xl" style={{ background: 'var(--panel-2)' }} />
</div>
)
}ActivitySkeleton function · typescript · L197-L211 (15 LOC)app/staff/page.tsx
function ActivitySkeleton() {
return (
<div className="animate-pulse space-y-4">
{Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="flex gap-3">
<div className="w-2 h-2 rounded-full mt-2" style={{ background: 'var(--panel-2)' }} />
<div className="flex-1">
<div className="h-4 w-3/4 rounded mb-2" style={{ background: 'var(--panel-2)' }} />
<div className="h-3 w-1/2 rounded" style={{ background: 'var(--panel-2)' }} />
</div>
</div>
))}
</div>
)
}StatusDot function · typescript · L215-L231 (17 LOC)app/staff/page.tsx
function StatusDot({ oldestPendingDays }: { oldestPendingDays: number }) {
let color: string
let title: string
if (oldestPendingDays > 7) {
color = 'bg-red-500'
title = `Oldest pending: ${oldestPendingDays}d (> 7 days)`
} else if (oldestPendingDays >= 3) {
color = 'bg-amber-500'
title = `Oldest pending: ${oldestPendingDays}d (3-7 days)`
} else {
color = 'bg-emerald-500'
title = oldestPendingDays > 0 ? `Oldest pending: ${oldestPendingDays}d` : 'No overdue items'
}
return <span className={`w-2.5 h-2.5 rounded-full ${color}`} title={title} />
}StaffPortalHub function · typescript · L235-L508 (274 LOC)app/staff/page.tsx
export default function StaffPortalHub() {
const { locale, dir } = useI18n()
const isRtl = locale === 'ar'
// Access: hardcoded true for now (to be replaced with real auth)
const [isAuthorized] = useState(true)
// Data state
const [stats, setStats] = useState<StaffStats | null>(null)
const [serviceCounts, setServiceCounts] = useState<ServiceCounts>({})
const [activityEntries, setActivityEntries] = useState<ActivityEntry[]>([])
const [loadingStats, setLoadingStats] = useState(true)
const [loadingActivity, setLoadingActivity] = useState(true)
const [refreshingActivity, setRefreshingActivity] = useState(false)
// Staff info (demo)
const staffName = isRtl ? 'أحمد المنصوري' : 'Ahmed Al Mansouri'
const staffRole = 'ADMIN'
const staffDept = isRtl ? 'ربط الأعمال والخدمات' : 'Business Connect & Services'
const fetchStats = useCallback(async () => {
try {
const res = await fetch('/api/staff/stats')
const data = await res.json()
if (data.sAIPanel function · typescript · L12-L41 (30 LOC)components/AIPanel.tsx
export default function AIPanel({ title, content, isLoading, loadingText }: AIPanelProps) {
const { t } = useI18n()
if (!content && !isLoading) return null
return (
<div className="bg-gradient-to-r from-purple-50 to-indigo-50 dark:from-purple-900/30 dark:to-indigo-900/30 border border-purple-200 dark:border-purple-800 rounded-lg p-4">
<div className="flex items-center gap-2 mb-2">
<svg className="w-5 h-5 text-purple-600 dark:text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
<h3 className="font-semibold text-purple-800 dark:text-purple-300">{title}</h3>
<span className="text-xs text-purple-600 dark:text-purple-400 bg-purpHeader function · typescript · L8-L181 (174 LOC)components/Header.tsx
export default function Header() {
const { locale, setLocale, t } = useI18n()
const pathname = usePathname()
const isHome = pathname === '/'
const isServices = pathname.startsWith('/services')
const isCustomer = pathname.startsWith('/customer')
const isStaff = pathname.startsWith('/staff')
const isDashboard = pathname.startsWith('/dashboard')
const isRtl = locale === 'ar'
// On landing page, header is hidden (landing page has its own nav)
if (isHome) {
return null
}
return (
<header className="bg-gradient-to-r from-[#001B30] to-[#002040] text-white shadow-lg">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-14">
<div className="flex items-center gap-8">
<Link href="/" className="flex items-center gap-2">
{/* ADCCI-style Logo - Enhanced stroke for better visibility */}
<svg className="w-10 h-10" viewBox="0 0 48 48" fill="none">
AIPanelStatic function · typescript · L12-L200 (189 LOC)components/kpi/AIPanelStatic.tsx
export function AIPanelStatic({ data }: AIPanelStaticProps) {
const { t, dir } = useI18n()
const { resolvedTheme } = useTheme()
const isDark = resolvedTheme === 'dark'
const gridColor = isDark ? '#334155' : '#e2e8f0'
const textColor = isDark ? '#94a3b8' : '#64748b'
const tooltipBg = isDark ? '#1e293b' : '#ffffff'
const tooltipBorder = isDark ? '#334155' : '#e2e8f0'
const statCards = [
{
label: t.kpiDashboard?.prechecksRun || 'AI Pre-checks Run',
value: data.prechecksRun.toLocaleString(),
icon: (
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
color: 'text-blue-600 dark:text-blue-400 bg-blue-100 dark:bg-blue-900/30'
},
{
label: t.kpiDashboard?.documentClassifications || 'Document Classifications',
value: data.documentClassificationScoreCard function · typescript · L21-L57 (37 LOC)components/kpi/ESGPanelStatic.tsx
function ScoreCard({ title, score, trend, color, metrics, metricLabels }: ScoreCardProps) {
const isPositive = trend.startsWith('+')
return (
<div className="bg-slate-50 dark:bg-slate-700/50 rounded-lg p-4">
<div className="flex items-center justify-between mb-3">
<h4 className="font-medium text-slate-700 dark:text-slate-200">{title}</h4>
<div className={`flex items-center text-sm ${isPositive ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}>
{isPositive ? (
<svg className="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 10l7-7m0 0l7 7m-7-7v18" />
</svg>
) : (
<svg className="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
ESGPanelStatic function · typescript · L59-L186 (128 LOC)components/kpi/ESGPanelStatic.tsx
export function ESGPanelStatic({ data }: ESGPanelStaticProps) {
const { t, dir } = useI18n()
const { resolvedTheme } = useTheme()
const isDark = resolvedTheme === 'dark'
const radarData = [
{ category: t.kpiDashboard?.environmental || 'Environmental', score: data.breakdown.environmental.score },
{ category: t.kpiDashboard?.social || 'Social', score: data.breakdown.social.score },
{ category: t.kpiDashboard?.governance || 'Governance', score: data.breakdown.governance.score }
]
const envMetricLabels: Record<string, string> = {
carbonReduction: t.wizard?.carbonEmissions || 'Carbon Reduction',
energyEfficiency: t.wizard?.energyReduction || 'Energy Efficiency',
wasteManagement: t.wizard?.wasteManagement || 'Waste Management',
waterConservation: t.wizard?.waterConservation || 'Water Conservation'
}
const socialMetricLabels: Record<string, string> = {
workforceDiversity: t.wizard?.workforceDiversity || 'Workforce Diversity',
communityProFunnelStatic function · typescript · L22-L116 (95 LOC)components/kpi/FunnelStatic.tsx
export function FunnelStatic({ data }: FunnelStaticProps) {
const { t, dir } = useI18n()
const { resolvedTheme } = useTheme()
const isDark = resolvedTheme === 'dark'
const tooltipBg = isDark ? '#1e293b' : '#ffffff'
const tooltipBorder = isDark ? '#334155' : '#e2e8f0'
// Transform data for recharts compatibility
const pieData = data.bySector.map(item => ({
sector: item.sector,
count: item.count,
approved: item.approved
}))
const getStatusLabel = (status: string) => {
const statusMap: Record<string, string> = {
SUBMITTED: t.status?.SUBMITTED || 'Submitted',
UNDER_REVIEW: t.status?.UNDER_REVIEW || 'Under Review',
CORRECTIONS_REQUESTED: t.status?.CORRECTIONS_REQUESTED || 'Corrections Requested',
APPROVED: t.status?.APPROVED || 'Approved',
REJECTED: t.status?.REJECTED || 'Rejected'
}
return statusMap[status] || status
}
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6" dir={dir}>
{/* ApplRecentApplicationsTableStatic function · typescript · L18-L118 (101 LOC)components/kpi/RecentApplicationsTableStatic.tsx
export function RecentApplicationsTableStatic({ data }: RecentApplicationsTableStaticProps) {
const { t, dir, locale } = useI18n()
const getStatusLabel = (status: string) => {
const statusMap: Record<string, string> = {
SUBMITTED: t.status?.SUBMITTED || 'Submitted',
UNDER_REVIEW: t.status?.UNDER_REVIEW || 'Under Review',
CORRECTIONS_REQUESTED: t.status?.CORRECTIONS_REQUESTED || 'Corrections Requested',
APPROVED: t.status?.APPROVED || 'Approved',
REJECTED: t.status?.REJECTED || 'Rejected'
}
return statusMap[status] || status
}
const formatDate = (dateStr: string) => {
const date = new Date(dateStr)
return date.toLocaleDateString(locale === 'ar' ? 'ar-AE' : 'en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
})
}
return (
<div className="bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 transition-colors overflow-hidden" di