Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Preferences', () => {
it('renders accessibility settings without a language selector', () => {
render(<Preferences />)

expect(screen.getByText('Accessibility')).toBeTruthy()
expect(screen.getByText('Preferences')).toBeTruthy()
expect(screen.getByText('High contrast mode')).toBeTruthy()
expect(screen.getByText('Large text mode')).toBeTruthy()
expect(screen.queryByDisplayValue('English')).toBeNull()
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import i18n from 'i18next';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import hiStrings from './locales/hi';
import taStrings from './locales/ta';
Expand Down Expand Up @@ -607,6 +607,7 @@ export const enStrings: Record<string, string> = {
minLabel: 'min',
claimNow: 'Claim Now',
alreadyClaimedStatus: 'Already Claimed',
noExpiringSoon: 'No donations expiring soon. All good!',
// —— Leaderboards ——
leaderboardsTitle: 'Leaderboards',
leaderboardsDesc: 'Top contributors ranked by karma points and activity.',
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -351,17 +351,33 @@
}
.a11y-contrast .card,
.a11y-contrast .card-elevated {
border-color: rgba(0, 0, 0, 0.5) !important;
border-width: 2px !important;
}
.dark.a11y-contrast .card,
.dark.a11y-contrast .card-elevated {
border-color: rgba(255, 255, 255, 0.5) !important;
border-width: 2px !important;
}
.a11y-contrast a,
.a11y-contrast button {
text-decoration-thickness: 2px;
outline-offset: 3px;
outline-color: rgba(0,0,0,0.8);
}
.dark.a11y-contrast a,
.dark.a11y-contrast button {
outline-color: rgba(255,255,255,0.8);
}
.a11y-contrast input,
.a11y-contrast select,
.a11y-contrast textarea {
border-color: rgba(0, 0, 0, 0.5) !important;
border-width: 2px !important;
}
.dark.a11y-contrast input,
.dark.a11y-contrast select,
.dark.a11y-contrast textarea {
border-color: rgba(255, 255, 255, 0.5) !important;
border-width: 2px !important;
}
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/pages/dashboard/AdminDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
RefreshCw, MessageSquare,
} from 'lucide-react';

// ─── Types ───────────────────────────────────────────────────────────────────


type AdminTab = 'notifications' | 'pending' | 'users' | 'donations' | 'flagged' | 'tickets';

Expand Down Expand Up @@ -43,7 +43,7 @@ interface FlaggedItem {
createdAt: string;
}

// ─── Style Maps ──────────────────────────────────────────────────────────────


const priorityStyle: Record<string, string> = {
high: 'bg-red-500/10 text-red-400 border-red-500/20',
Expand All @@ -66,7 +66,7 @@ const statusStyle: Record<string, string> = {
ESCALATED: 'bg-purple-500/10 text-purple-400 border-purple-500/20',
};

// ─── Ticket Modal ─────────────────────────────────────────────────────────────


function TicketModal({ ticket, onClose, onUpdate }: {
ticket: SupportTicket; onClose: () => void; onUpdate: () => void;
Expand Down Expand Up @@ -160,7 +160,7 @@ function TicketModal({ ticket, onClose, onUpdate }: {
);
}

// ─── Main ─────────────────────────────────────────────────────────────────────


export default function AdminDashboard() {
const [activeTab, setActiveTab] = useState<AdminTab>('notifications');
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/dashboard/DiscoveryMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
unsubscribeCreated()
unsubscribeClaimed()
}
}, [])

Check warning on line 87 in frontend/src/pages/dashboard/DiscoveryMap.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has missing dependencies: 'selectedDonation?.id', 't', and 'user.id'. Either include them or remove the dependency array

Check warning on line 87 in frontend/src/pages/dashboard/DiscoveryMap.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has missing dependencies: 'selectedDonation?.id', 't', and 'user.id'. Either include them or remove the dependency array

Check warning on line 87 in frontend/src/pages/dashboard/DiscoveryMap.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has missing dependencies: 'selectedDonation?.id', 't', and 'user.id'. Either include them or remove the dependency array

const loadDonations = async () => {
setLoading(true)
Expand Down Expand Up @@ -284,21 +284,21 @@
className="w-full h-full object-cover"
/>
{/* Image Counter */}
<div className="absolute bottom-4 right-4 bg-black/60 text-gray-900 dark:text-white text-xs px-3 py-1 rounded-full">
<div className="absolute bottom-4 right-4 bg-black/60 text-white text-xs px-3 py-1 rounded-full">
{currentImageIndex + 1} / {selectedDonation.imageUrls.length}
</div>
{/* Navigation Buttons */}
{selectedDonation.imageUrls.length > 1 && (
<>
<button
onClick={() => setCurrentImageIndex((prev) => (prev - 1 + selectedDonation.imageUrls.length) % selectedDonation.imageUrls.length)}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-gray-900 dark:text-white p-2 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
>
<ChevronLeft className="w-5 h-5" />
</button>
<button
onClick={() => setCurrentImageIndex((prev) => (prev + 1) % selectedDonation.imageUrls.length)}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-gray-900 dark:text-white p-2 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
>
<ChevronRight className="w-5 h-5" />
</button>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/dashboard/DonorHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
unsubscribeCreated()
unsubscribeClaimed()
}
}, [])

Check warning on line 45 in frontend/src/pages/dashboard/DonorHome.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'load'. Either include it or remove the dependency array

Check warning on line 45 in frontend/src/pages/dashboard/DonorHome.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'load'. Either include it or remove the dependency array

Check warning on line 45 in frontend/src/pages/dashboard/DonorHome.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'load'. Either include it or remove the dependency array

const activeCount = donations.filter((d) => d.status === 'AVAILABLE').length
const claimedCount = donations.filter((d) => d.status === 'CLAIMED').length
Expand Down Expand Up @@ -279,7 +279,7 @@
className="w-full h-full object-cover"
/>
{/* Image Counter */}
<div className="absolute bottom-4 right-4 bg-black/60 text-gray-900 dark:text-white text-xs px-3 py-1 rounded-full">
<div className="absolute bottom-4 right-4 bg-black/60 text-white text-xs px-3 py-1 rounded-full">
{currentImageIndex + 1} / {selectedDonation.imageUrls.length}
</div>
{/* Navigation Buttons */}
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/pages/dashboard/FeedbackRatings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

useEffect(() => {
loadData()
}, [])

Check warning on line 25 in frontend/src/pages/dashboard/FeedbackRatings.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the dependency array

Check warning on line 25 in frontend/src/pages/dashboard/FeedbackRatings.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the dependency array

Check warning on line 25 in frontend/src/pages/dashboard/FeedbackRatings.tsx

View workflow job for this annotation

GitHub Actions / Frontend

React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the dependency array

const loadData = async () => {
setLoading(true)
Expand Down Expand Up @@ -113,7 +113,7 @@
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-semibold text-white">{t('ngoFeedbackRatings')}</h1>
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white">{t('ngoFeedbackRatings')}</h1>
<p className="text-slate-400 mt-1">{t('feedbackDesc')}</p>
</div>

Expand Down Expand Up @@ -141,7 +141,7 @@
<div>
<p className="text-sm text-slate-400">{t('yourDonorRating')}</p>
<div className="flex items-center gap-3 mt-1">
<span className="text-3xl font-bold text-white">{donorRating.averageScore.toFixed(1)}</span>
<span className="text-3xl font-bold text-gray-900 dark:text-white">{donorRating.averageScore.toFixed(1)}</span>
<span className="text-amber-400 text-lg">{'★'.repeat(Math.round(donorRating.averageScore))}{'☆'.repeat(5 - Math.round(donorRating.averageScore))}</span>
</div>
<p className="text-xs text-slate-500 mt-1">{t('basedOnReviews', { count: donorRating.totalReviews })}</p>
Expand All @@ -151,7 +151,7 @@
)}
{isNGO && (
<div className="card p-5 xl:col-span-1">
<h2 className="text-white font-semibold mb-4 flex items-center gap-2">
<h2 className="text-gray-900 dark:text-white font-semibold mb-4 flex items-center gap-2">
<MessageCircle className="w-5 h-5 text-emerald-400" />
{t('leaveReview')}
</h2>
Expand Down Expand Up @@ -199,7 +199,7 @@
{/* Rating Summary & Reviews */}
<div className={`card p-5 space-y-4 ${isNGO ? 'xl:col-span-2' : 'xl:col-span-3'}`}>
<div className="flex items-center justify-between">
<h2 className="text-white font-semibold">{t('ratingSummary')}</h2>
<h2 className="text-gray-900 dark:text-white font-semibold">{t('ratingSummary')}</h2>
<span className="badge badge-success flex items-center gap-1">
<Star className="w-3 h-3" />
{avgRating.toFixed(1)} / 5
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/pages/dashboard/History.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Donation } from '../../services/api'
import { socketService } from '../../services/socket'
import { TrendingUp, BarChart2, Package } from 'lucide-react'

// ─── Inline SVG Bar Chart ─────────────────────────────────────────────────────


interface BarChartProps {
data: { label: string; value: number; color?: string }[]
Expand Down Expand Up @@ -100,7 +100,7 @@ function BarChart({ data, height = 180, unit = '', title, subtitle, accentColor
)
}

// ─── Line/Area Trend Chart ────────────────────────────────────────────────────


interface LineChartProps {
data: { label: string; value: number }[]
Expand Down Expand Up @@ -183,7 +183,7 @@ function LineChart({ data, title, subtitle, accentColor = '#6366f1' }: LineChart
)
}

// ─── Monthly Data Helpers ─────────────────────────────────────────────────────


const MONTH_ABBR = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
const LAST_6_MONTHS = Array.from({ length: 6 }, (_, i) => {
Expand All @@ -202,7 +202,7 @@ function aggregateByMonth(donations: Donation[], statusFilter?: string) {
})
}

// ─── Main History Component ───────────────────────────────────────────────────


const userRole = (): string => {
try {
Expand Down
22 changes: 11 additions & 11 deletions frontend/src/pages/dashboard/Impact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Award, Download, Leaf, Droplets, Globe
} from 'lucide-react'

// ─── BADGE CATALOG (mirrors backend BADGE_RULES exactly) ─────────────────────


const BADGE_CATALOG_KEYS = [
{ threshold: 10, nameKey: 'newcomer', icon: '🌱', descKey: 'newcomerDesc' },
Expand All @@ -19,7 +19,7 @@ const BADGE_CATALOG_KEYS = [
{ threshold: 500, nameKey: 'superhero', icon: '💫', descKey: 'superheroDesc' },
]

// ─── INLINE SVG BAR CHART ─────────────────────────────────────────────────────


function SvgBarChart({
data, title, subtitle, color = '#10b981',
Expand Down Expand Up @@ -137,7 +137,7 @@ function SvgLineChart({
)
}

// ─── CERTIFICATE MODAL ────────────────────────────────────────────────────────


function CertificateModal({ user, role, onClose }: { user: User; role: string; onClose: () => void }) {
const { t } = useTranslation()
Expand Down Expand Up @@ -208,7 +208,7 @@ function CertificateModal({ user, role, onClose }: { user: User; role: string; o
<div className="w-full max-w-3xl bg-white rounded-2xl shadow-2xl overflow-auto max-h-[92vh]">
{/* Toolbar */}
<div className="flex justify-between items-center px-6 py-4 border-b border-slate-200 bg-slate-50 rounded-t-2xl">
<h3 className="text-base font-semibold text-gray-200 dark:text-slate-800 flex items-center gap-2">
<h3 className="text-base font-semibold text-gray-800 dark:text-slate-200 flex items-center gap-2">
<Award className="w-5 h-5 text-emerald-600" />
{t('certificateOfAppreciation')}
</h3>
Expand All @@ -218,7 +218,7 @@ function CertificateModal({ user, role, onClose }: { user: User; role: string; o
<Download className="w-4 h-4" />{t('printSavePDF')}
</button>
<button onClick={onClose}
className="bg-slate-200 hover:bg-slate-300 text-gray-300 dark:text-slate-700 px-4 py-2 rounded-lg text-sm font-medium transition-colors">
className="bg-slate-200 hover:bg-slate-300 text-gray-700 dark:text-slate-300 px-4 py-2 rounded-lg text-sm font-medium transition-colors">
{t('close')}
</button>
</div>
Expand Down Expand Up @@ -275,12 +275,12 @@ function CertificateModal({ user, role, onClose }: { user: User; role: string; o
<div>
<div style={{ width: 150, borderBottom: '1px solid #d1d5db', marginBottom: 5 }} />
<p className="text-xs text-gray-500 dark:text-slate-500" style={{ fontFamily: 'sans-serif' }}>{t('platformDirector')}</p>
<p className="text-xs font-semibold text-gray-300 dark:text-slate-700" style={{ fontFamily: 'sans-serif' }}>{t('surplusSyncNetwork')}</p>
<p className="text-xs font-semibold text-gray-700 dark:text-slate-300" style={{ fontFamily: 'sans-serif' }}>{t('surplusSyncNetwork')}</p>
</div>
<div className="text-2xl">🏅</div>
<div className="text-right">
<p className="text-xs text-gray-500 dark:text-slate-500" style={{ fontFamily: 'sans-serif' }}>{t('dateOfIssue')}</p>
<p className="text-sm font-semibold text-gray-300 dark:text-slate-700" style={{ fontFamily: 'sans-serif' }}>{today}</p>
<p className="text-sm font-semibold text-gray-700 dark:text-slate-300" style={{ fontFamily: 'sans-serif' }}>{today}</p>
</div>
</div>
</div>
Expand All @@ -290,7 +290,7 @@ function CertificateModal({ user, role, onClose }: { user: User; role: string; o
)
}

// ─── GAMIFICATION: KARMA PROGRESS BAR ────────────────────────────────────────


function KarmaProgress({ karma, badgeCatalog }: { karma: number; badgeCatalog?: { id: string; name: string; icon: string; description: string; earned: boolean; requirement: number }[] }) {
const { t } = useTranslation()
Expand Down Expand Up @@ -373,7 +373,7 @@ function KarmaProgress({ karma, badgeCatalog }: { karma: number; badgeCatalog?:
)
}

// ─── COMMUNITY COUNTERS ───────────────────────────────────────────────────────


function CommunityCounters({ stats }: { stats: CommunityStats }) {
const { t } = useTranslation()
Expand Down Expand Up @@ -412,7 +412,7 @@ function CommunityCounters({ stats }: { stats: CommunityStats }) {
)
}

// ─── NGO GROWTH CHARTS ────────────────────────────────────────────────────────


function NGOGrowthCharts({ monthly }: { monthly: MonthlyStatPoint[] }) {
const { t } = useTranslation()
Expand Down Expand Up @@ -476,7 +476,7 @@ function NGOGrowthCharts({ monthly }: { monthly: MonthlyStatPoint[] }) {
)
}

// ─── MAIN IMPACT PAGE ─────────────────────────────────────────────────────────


export default function Impact() {
const { t } = useTranslation()
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/dashboard/NearExpiryAlerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default function NearExpiryAlerts() {
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-semibold text-white">{t('nearExpiryAlerts')}</h1>
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white">{t('nearExpiryAlerts')}</h1>
<p className="text-slate-400 mt-1">{t('nearExpiryDesc')}</p>
</div>
<button onClick={loadAlerts} className="btn-secondary py-2 px-3 text-sm flex items-center gap-2">
Expand All @@ -134,7 +134,7 @@ export default function NearExpiryAlerts() {
key={f}
type="button"
onClick={() => setUrgency(f)}
className={`px-3 py-1.5 rounded-md text-sm capitalize ${urgency === f ? 'bg-emerald-500 text-white' : 'bg-slate-900 border border-slate-800 text-slate-300'}`}
className={`px-3 py-1.5 rounded-md text-sm capitalize ${urgency === f ? 'bg-emerald-500 text-white' : 'bg-gray-100 dark:bg-slate-900 border border-gray-200 dark:border-slate-800 text-gray-700 dark:text-slate-300'}`}
>
{f === 'all' ? t('all') : f === 'critical' ? t('critical') : t('warning')}
</button>
Expand All @@ -149,7 +149,7 @@ export default function NearExpiryAlerts() {
<div key={alert.id} className={`card p-4 border ${critical ? 'border-red-500/40' : 'border-amber-500/30'}`}>
<div className="flex items-start justify-between gap-3">
<div>
<p className="text-white font-medium flex items-center gap-2">
<p className="text-gray-900 dark:text-white font-medium flex items-center gap-2">
<AlertTriangle className={`w-4 h-4 ${critical ? 'text-red-400' : 'text-amber-400'}`} />
{alert.food}
</p>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/dashboard/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default function Notifications() {
<div className="text-center py-12 text-gray-500 dark:text-slate-500">{t('loadingNotifications')}</div>
) : filtered.length === 0 ? (
<div className="text-center py-12">
<Bell className="w-12 h-12 text-gray-300 dark:text-slate-700 mx-auto mb-3" />
<Bell className="w-12 h-12 text-gray-700 dark:text-slate-300 mx-auto mb-3" />
<p className="text-gray-500 dark:text-slate-500">
{filter === 'unread' ? t('noUnreadNotifications') : t('noNotificationsYet')}
</p>
Expand Down
Loading
Loading