Function bodies 182 total
TimeSeriesStatic function · typescript · L23-L113 (91 LOC)components/kpi/TimeSeriesStatic.tsx
export function TimeSeriesStatic({ data }: TimeSeriesStaticProps) {
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'
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6" dir={dir}>
{/* Application Trend Chart */}
<div className="bg-white dark:bg-slate-800 rounded-xl p-6 shadow-sm border border-slate-200 dark:border-slate-700 transition-colors">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4">
{t.kpiDashboard?.applicationTrend || 'Application Trend'}
</h3>
<div className="h-[300px]">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data.applicationTrend} margin={{ top: 5, right: 30, left: 20, bMetricCard function · typescript · L19-L50 (32 LOC)components/kpi/TopMetricsStatic.tsx
function MetricCard({ title, value, subtitle, icon, trend, trendUp }: MetricCardProps) {
return (
<div className="bg-white dark:bg-slate-800 rounded-xl p-6 shadow-sm border border-slate-200 dark:border-slate-700 transition-colors">
<div className="flex items-start justify-between">
<div className="flex-1">
<p className="text-sm font-medium text-slate-500 dark:text-slate-400">{title}</p>
<p className="mt-2 text-3xl font-bold text-slate-900 dark:text-white">{value}</p>
{subtitle && (
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">{subtitle}</p>
)}
{trend && (
<div className={`mt-2 flex items-center text-sm ${trendUp ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}>
{trendUp ? (
<svg className="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoTopMetricsStatic function · typescript · L52-L151 (100 LOC)components/kpi/TopMetricsStatic.tsx
export function TopMetricsStatic({ data }: TopMetricsStaticProps) {
const { t, dir } = useI18n()
const metrics = [
{
title: t.kpiDashboard?.totalApplications || 'Total Applications',
value: data.totalApplications.toLocaleString(),
subtitle: `+${data.applicationsThisMonth} ${t.kpiDashboard?.thisMonth || 'this month'}`,
trend: '+12%',
trendUp: true,
icon: (
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
)
},
{
title: t.kpiDashboard?.approvalRate || 'Approval Rate',
value: `${data.approvalRate}%`,
trend: '+3.2%',
trendUp: true,
icon: (
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLineccreateSectorIcon function · typescript · L28-L43 (16 LOC)components/market-directory/MarketMap.tsx
function createSectorIcon(sector: string, isGolden: boolean) {
const color = sectorHexColors[sector] || '#6b7280'
return L.divIcon({
className: 'market-cluster-icon',
html: `<div style="
width: 28px; height: 28px; border-radius: 50%;
background: ${color}; border: 2px solid white;
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
display: flex; align-items: center; justify-content: center;
${isGolden ? 'box-shadow: 0 0 0 3px #f59e0b, 0 2px 6px rgba(0,0,0,0.3);' : ''}
"><span style="color:white;font-size:11px;font-weight:bold;">${sector.charAt(0)}</span></div>`,
iconSize: [28, 28],
iconAnchor: [14, 14],
popupAnchor: [0, -16],
})
}FlyToCompany function · typescript · L45-L53 (9 LOC)components/market-directory/MarketMap.tsx
function FlyToCompany({ company }: { company: Company | null }) {
const map = useMap()
useEffect(() => {
if (company) {
map.flyTo([company.lat, company.lng], 15, { duration: 1.2 })
}
}, [company, map])
return null
}MarketMap function · typescript · L69-L242 (174 LOC)components/market-directory/MarketMap.tsx
export default function MarketMap({
companies,
areaStats,
selectedCompany,
onSelectCompany,
mapMode,
isRtl,
}: MarketMapProps) {
// Compute dominant sector per area for sector clusters mode
const areaDominantSector = useMemo(() => {
const map: Record<string, string> = {}
for (const area of areaStats) {
if (area.topSectors.length > 0) {
map[area.area] = area.topSectors[0]
}
}
return map
}, [areaStats])
return (
<div className="relative w-full h-full rounded-xl overflow-hidden" style={{ minHeight: 400 }}>
<MapContainer
center={[24.4539, 54.3773]}
zoom={11}
scrollWheelZoom={true}
className="w-full h-full"
style={{ height: '100%', width: '100%', borderRadius: '0.75rem' }}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<FlgetStepStatus function · typescript · L7-L21 (15 LOC)components/ProgressTracker.tsx
function getStepStatus(status: Status, step: number): 'completed' | 'current' | 'upcoming' {
const statusOrder: Record<Status, number> = {
SUBMITTED: 1,
UNDER_REVIEW: 2,
CORRECTIONS_REQUESTED: 3,
APPROVED: 4,
REJECTED: 4,
}
const currentStep = statusOrder[status]
if (step < currentStep) return 'completed'
if (step === currentStep) return 'current'
return 'upcoming'
}Repobility analyzer · published findings · https://repobility.com
ProgressTracker function · typescript · L23-L89 (67 LOC)components/ProgressTracker.tsx
export default function ProgressTracker({ status }: { status: string }) {
const { t, dir } = useI18n()
const typedStatus = status as Status
const steps = [
{ step: 1, label: t.customer.detail.step1 },
{ step: 2, label: t.customer.detail.step2 },
{ step: 3, label: t.customer.detail.step3 },
{ step: 4, label: typedStatus === 'REJECTED' ? t.status.REJECTED : t.customer.detail.step4 },
]
return (
<div className="w-full">
<div className={`flex items-center ${dir === 'rtl' ? 'flex-row-reverse' : ''}`}>
{steps.map((item, index) => {
const stepStatus = getStepStatus(typedStatus, item.step)
const isLast = index === steps.length - 1
return (
<div key={item.step} className={`flex items-center ${!isLast ? 'flex-1' : ''}`}>
<div className="flex flex-col items-center">
<div
className={`w-10 h-10 rounded-full flex items-center justify-center font-semibold text-sm trrelativeTime function · typescript · L51-L64 (14 LOC)components/staff/ApplicationDetailPanel.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' })
}ApplicationDetailPanel function · typescript · L66-L371 (306 LOC)components/staff/ApplicationDetailPanel.tsx
export default function ApplicationDetailPanel({
applicationId,
serviceType,
onClose,
onStatusChange,
slaDays = null,
children,
}: ApplicationDetailPanelProps) {
const { locale, dir } = useI18n()
const isRtl = locale === 'ar'
const [application, setApplication] = useState<ApplicationDetail | null>(null)
const [staffList, setStaffList] = useState<StaffOption[]>([])
const [isLoading, setIsLoading] = useState(true)
const [newStatus, setNewStatus] = useState('')
const [newAssignee, setNewAssignee] = useState('')
const [internalNotes, setInternalNotes] = useState('')
const [rejectionReason, setRejectionReason] = useState('')
const [isSaving, setIsSaving] = useState(false)
const fetchApplication = useCallback(async () => {
try {
const res = await fetch(`/api/staff/applications/${applicationId}`)
const data = await res.json()
if (data.success) {
setApplication(data.application)
setInternalNotes(data.application.internalApplicationStatusBadge function · typescript · L29-L42 (14 LOC)components/staff/ApplicationStatusBadge.tsx
export default function ApplicationStatusBadge({ status }: ApplicationStatusBadgeProps) {
const { locale } = useI18n()
const typedStatus = status as ApplicationStatus
const colors = statusColors[typedStatus] || statusColors.SUBMITTED
const label = statusLabels[typedStatus]
? (locale === 'ar' ? statusLabels[typedStatus].ar : statusLabels[typedStatus].en)
: status
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ${colors}`}>
{label}
</span>
)
}TableSkeleton function · typescript · L41-L60 (20 LOC)components/staff/ApplicationTable.tsx
function TableSkeleton() {
return (
<div className="rounded-2xl theme-panel overflow-hidden">
<div className="animate-pulse">
<div className="h-12" style={{ background: 'var(--panel-2)' }} />
{Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="flex items-center gap-4 px-6 py-4" style={{ borderTop: '1px solid var(--border)' }}>
<div className="w-4 h-4 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-20 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-32 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-16 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-24 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-20 rounded" style={{ background: 'var(--panel-2)' }} />
<div className="h-4 w-20 rounded" style={{ background: 'var(--panelApplicationTable function · typescript · L62-L324 (263 LOC)components/staff/ApplicationTable.tsx
export default function ApplicationTable({
applications,
totalCount,
page,
pageSize,
onPageChange,
onRowClick,
onBulkStatusUpdate,
sortBy,
sortOrder,
onSort,
slaDays = null,
isLoading = false,
}: ApplicationTableProps) {
const { locale } = useI18n()
const isRtl = locale === 'ar'
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
const [bulkStatus, setBulkStatus] = useState('')
const totalPages = Math.ceil(totalCount / pageSize)
const allSelected = useMemo(
() => applications.length > 0 && applications.every(a => selectedIds.has(a.id)),
[applications, selectedIds]
)
const toggleAll = () => {
if (allSelected) {
setSelectedIds(new Set())
} else {
setSelectedIds(new Set(applications.map(a => a.id)))
}
}
const toggleOne = (id: string) => {
setSelectedIds(prev => {
const next = new Set(prev)
if (next.has(id)) next.delete(id)
else next.add(id)
return next
})
}
SLAIndicator function · typescript · L10-L56 (47 LOC)components/staff/SLAIndicator.tsx
export default function SLAIndicator({ submittedAt, slaDays }: SLAIndicatorProps) {
const { locale } = useI18n()
const isRtl = locale === 'ar'
if (!slaDays || slaDays <= 0) {
return (
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border bg-gray-100 dark:bg-white/10 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-white/10">
{isRtl ? 'غير محدد' : 'N/A'}
</span>
)
}
const submitted = new Date(submittedAt)
const now = new Date()
const elapsedMs = now.getTime() - submitted.getTime()
const elapsedDays = elapsedMs / (1000 * 60 * 60 * 24)
const ratio = elapsedDays / slaDays
const remaining = slaDays - elapsedDays
let colorClass: string
let label: string
if (ratio > 1) {
// Breached
const overdueDays = Math.ceil(elapsedDays - slaDays)
colorClass = 'bg-red-100 dark:bg-red-500/20 text-red-800 dark:text-red-300 border-red-200 dark:border-red-500/30'
label = isRtl ? `متأStaffAccessGuard function · typescript · L11-L50 (40 LOC)components/staff/StaffAccessGuard.tsx
export default function StaffAccessGuard({ isAuthorized, children }: StaffAccessGuardProps) {
const { locale, dir } = useI18n()
const isRtl = locale === 'ar'
if (isAuthorized) {
return <>{children}</>
}
return (
<div className="min-h-screen flex items-center justify-center px-4" style={{ background: 'var(--bg)' }} dir={dir}>
<div className="max-w-md w-full text-center">
<div className="w-20 h-20 rounded-full flex items-center justify-center mx-auto mb-6" style={{ background: 'var(--accent-red)', opacity: 0.15 }}>
<svg className="w-10 h-10" style={{ color: 'var(--accent-red)' }} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
</svg>
</div>
<h2 className="text-2xl font-bold mb-2" style={{ color: 'var(--text)' }}>
{isRtl ? All rows above produced by Repobility · https://repobility.com
StaffFilterBar function · typescript · L25-L125 (101 LOC)components/staff/StaffFilterBar.tsx
export default function StaffFilterBar({
searchQuery,
onSearchChange,
searchPlaceholder = 'Search applications...',
searchPlaceholderAr = 'البحث في الطلبات...',
filters,
activeFilters,
onFilterChange,
onClearAll,
resultCount,
}: StaffFilterBarProps) {
const { locale } = useI18n()
const isRtl = locale === 'ar'
const hasActiveFilters = searchQuery.length > 0 || Object.values(activeFilters).some(v => v !== '')
return (
<div className="mb-6">
<div className="flex flex-col lg:flex-row gap-4">
{/* Search */}
<div className="relative flex-1">
<svg className={`absolute top-1/2 -translate-y-1/2 w-5 h-5 ${isRtl ? 'right-3' : 'left-3'}`} style={{ color: 'var(--muted)' }} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
type="text"
value={searcStatusBadge function · typescript · L16-L29 (14 LOC)components/StatusBadge.tsx
export default function StatusBadge({ status }: { status: string }) {
const { t } = useI18n()
const typedStatus = status as Status
return (
<span
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
statusClasses[typedStatus] || 'chip-submitted'
}`}
>
{t.status[typedStatus] || status}
</span>
)
}ThemeProvider function · typescript · L13-L25 (13 LOC)components/ThemeProvider.tsx
export function ThemeProvider({ children }: { children: ReactNode }) {
return (
<NextThemesProvider
attribute="class"
defaultTheme="dark"
enableSystem={true}
disableTransitionOnChange={false}
storageKey="esg-portal-theme"
>
{children}
</NextThemesProvider>
)
}ThemeToggle function · typescript · L17-L60 (44 LOC)components/ThemeToggle.tsx
export function ThemeToggle({ className = '' }: ThemeToggleProps) {
const { theme, setTheme, resolvedTheme } = useTheme()
const [mounted, setMounted] = useState(false)
// Prevent hydration mismatch by only rendering after mount
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true)
}, [])
if (!mounted) {
// Return placeholder to prevent layout shift
return (
<div className={`w-9 h-9 rounded-lg bg-white/10 ${className}`} />
)
}
const isDark = resolvedTheme === 'dark'
const toggleTheme = () => {
setTheme(isDark ? 'light' : 'dark')
}
return (
<button
onClick={toggleTheme}
className={`p-2 rounded-lg transition-colors hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/20 ${className}`}
aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
title={isDark ? 'Light mode' : 'Dark mode'}
>
{isDark ? (
// Sun icon for switchinlogActivity function · typescript · L4-L20 (17 LOC)lib/activity-log.ts
export async function logActivity(
applicationId: string,
serviceType: ServiceType,
action: string,
performedBy: string,
notes?: string
) {
return prisma.activityLog.create({
data: {
applicationId,
serviceType,
action,
performedBy,
notes: notes ?? null,
},
})
}futureDate function · typescript · L113-L117 (5 LOC)lib/global-tenders-data.ts
function futureDate(days: number): string {
const d = new Date()
d.setDate(d.getDate() + days)
return d.toISOString().split('T')[0]
}pastDate function · typescript · L119-L123 (5 LOC)lib/global-tenders-data.ts
function pastDate(days: number): string {
const d = new Date()
d.setDate(d.getDate() - days)
return d.toISOString().split('T')[0]
}I18nProvider function · typescript · L21-L52 (32 LOC)lib/i18n.tsx
export function I18nProvider({ children }: { children: ReactNode }) {
const [locale, setLocaleState] = useState<Locale>('en')
const [mounted, setMounted] = useState(false)
useEffect(() => {
const saved = localStorage.getItem('locale') as Locale | null
if (saved && (saved === 'en' || saved === 'ar')) {
// eslint-disable-next-line react-hooks/set-state-in-effect
setLocaleState(saved)
}
// eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true)
}, [])
const setLocale = (newLocale: Locale) => {
setLocaleState(newLocale)
localStorage.setItem('locale', newLocale)
}
const value: I18nContextType = {
locale,
setLocale,
t: translations[locale],
dir: locale === 'ar' ? 'rtl' : 'ltr',
}
if (!mounted) {
return null
}
return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>
}Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
useI18n function · typescript · L54-L60 (7 LOC)lib/i18n.tsx
export function useI18n() {
const context = useContext(I18nContext)
if (!context) {
throw new Error('useI18n must be used within an I18nProvider')
}
return context
}getKPISummary function · typescript · L146-L150 (5 LOC)lib/kpi-mock-client.ts
export async function getKPISummary(): Promise<KPISummary> {
// Simulate network delay for realistic feel
await new Promise(resolve => setTimeout(resolve, 100))
return kpiSummary as KPISummary
}getKPITimeSeries function · typescript · L152-L155 (4 LOC)lib/kpi-mock-client.ts
export async function getKPITimeSeries(): Promise<KPITimeSeries> {
await new Promise(resolve => setTimeout(resolve, 100))
return kpiTimeseries as KPITimeSeries
}getKPIFunnel function · typescript · L157-L160 (4 LOC)lib/kpi-mock-client.ts
export async function getKPIFunnel(): Promise<KPIFunnel> {
await new Promise(resolve => setTimeout(resolve, 100))
return kpiFunnel as KPIFunnel
}getKPIESG function · typescript · L162-L165 (4 LOC)lib/kpi-mock-client.ts
export async function getKPIESG(): Promise<KPIESG> {
await new Promise(resolve => setTimeout(resolve, 100))
return kpiEsg as KPIESG
}getKPIAI function · typescript · L167-L170 (4 LOC)lib/kpi-mock-client.ts
export async function getKPIAI(): Promise<KPIAI> {
await new Promise(resolve => setTimeout(resolve, 100))
return kpiAi as KPIAI
}getRecentApplications function · typescript · L172-L175 (4 LOC)lib/kpi-mock-client.ts
export async function getRecentApplications(): Promise<RecentApplicationsData> {
await new Promise(resolve => setTimeout(resolve, 100))
return recentApplications as RecentApplicationsData
}getAllKPIData function · typescript · L178-L196 (19 LOC)lib/kpi-mock-client.ts
export async function getAllKPIData() {
const [summary, timeseries, funnel, esg, ai, applications] = await Promise.all([
getKPISummary(),
getKPITimeSeries(),
getKPIFunnel(),
getKPIESG(),
getKPIAI(),
getRecentApplications()
])
return {
summary,
timeseries,
funnel,
esg,
ai,
applications
}
}Repobility — the code-quality scanner for AI-generated software · https://repobility.com
main function · typescript · L5-L81 (77 LOC)scripts/clear-applications.ts
async function main() {
console.log('=== BEFORE CLEAR ===')
const [
activityLogs,
knowledgeSharingApps,
esgApps,
baseApps,
certificates,
reviewNotes,
applicationDocs,
legacyApps,
] = await Promise.all([
prisma.activityLog.count(),
prisma.knowledgeSharingApplication.count(),
prisma.esgApplication.count(),
prisma.baseApplication.count(),
prisma.certificate.count(),
prisma.reviewNote.count(),
prisma.applicationDocument.count(),
prisma.application.count(),
])
console.log(` ActivityLog: ${activityLogs}`)
console.log(` KnowledgeSharingApplication: ${knowledgeSharingApps}`)
console.log(` EsgApplication: ${esgApps}`)
console.log(` BaseApplication: ${baseApps}`)
console.log(` Certificate: ${certificates}`)
console.log(` ReviewNote: ${reviewNotes}`)
console.log(` ApplicationDocument: ${applicationDocs}`)
console.‹ prevpage 4 / 4