diff --git a/src/components/shared/age-indicator.tsx b/src/components/shared/age-indicator.tsx
new file mode 100644
index 0000000..53024bd
--- /dev/null
+++ b/src/components/shared/age-indicator.tsx
@@ -0,0 +1,24 @@
+import { cx } from '@/utils/cx';
+import { daysAgoFromNow, getAgeBracket } from '@/lib/format';
+
+const ageBracketColorMap = {
+ fresh: 'text-success-primary',
+ warm: 'text-warning-primary',
+ cold: 'text-error-primary',
+};
+
+interface AgeIndicatorProps {
+ dateStr: string;
+}
+
+export const AgeIndicator = ({ dateStr }: AgeIndicatorProps) => {
+ const days = daysAgoFromNow(dateStr);
+ const bracket = getAgeBracket(days);
+ const colorClass = ageBracketColorMap[bracket];
+
+ return (
+
+ {days}d
+
+ );
+};
diff --git a/src/components/shared/source-tag.tsx b/src/components/shared/source-tag.tsx
new file mode 100644
index 0000000..c006d0c
--- /dev/null
+++ b/src/components/shared/source-tag.tsx
@@ -0,0 +1,45 @@
+import { Badge } from '@/components/base/badges/badges';
+import type { LeadSource } from '@/types/entities';
+
+type SourceColor = 'blue' | 'pink' | 'success' | 'blue-light' | 'gray' | 'purple' | 'orange' | 'warning';
+
+const sourceColorMap: Record = {
+ FACEBOOK_AD: 'blue',
+ INSTAGRAM: 'pink',
+ GOOGLE_AD: 'success',
+ GOOGLE_MY_BUSINESS: 'blue-light',
+ WHATSAPP: 'success',
+ WEBSITE: 'gray',
+ REFERRAL: 'purple',
+ WALK_IN: 'orange',
+ PHONE: 'warning',
+ OTHER: 'gray',
+};
+
+const sourceLabelMap: Record = {
+ FACEBOOK_AD: 'Facebook',
+ INSTAGRAM: 'Instagram',
+ GOOGLE_AD: 'Google',
+ GOOGLE_MY_BUSINESS: 'GMB',
+ WHATSAPP: 'WhatsApp',
+ WEBSITE: 'Website',
+ REFERRAL: 'Referral',
+ WALK_IN: 'Walk-in',
+ PHONE: 'Phone',
+ OTHER: 'Other',
+};
+
+interface SourceTagProps {
+ source: LeadSource;
+ size?: 'sm' | 'md';
+}
+
+export const SourceTag = ({ source, size = 'sm' }: SourceTagProps) => {
+ const color = sourceColorMap[source];
+ const label = sourceLabelMap[source];
+ return (
+
+ {label}
+
+ );
+};
diff --git a/src/components/shared/status-badge.tsx b/src/components/shared/status-badge.tsx
new file mode 100644
index 0000000..03172cb
--- /dev/null
+++ b/src/components/shared/status-badge.tsx
@@ -0,0 +1,54 @@
+import { BadgeWithDot } from '@/components/base/badges/badges';
+import type { CampaignStatus, LeadStatus } from '@/types/entities';
+
+const toTitleCase = (str: string): string =>
+ str
+ .toLowerCase()
+ .replace(/_/g, ' ')
+ .replace(/\b\w/g, (c) => c.toUpperCase());
+
+type LeadStatusColor = 'blue' | 'brand' | 'success' | 'warning' | 'purple' | 'error' | 'gray';
+type CampaignStatusColor = 'gray' | 'success' | 'warning' | 'blue';
+
+const leadStatusColorMap: Record = {
+ NEW: 'blue',
+ CONTACTED: 'brand',
+ QUALIFIED: 'success',
+ NURTURING: 'warning',
+ APPOINTMENT_SET: 'purple',
+ CONVERTED: 'success',
+ LOST: 'error',
+};
+
+const campaignStatusColorMap: Record = {
+ DRAFT: 'gray',
+ ACTIVE: 'success',
+ PAUSED: 'warning',
+ COMPLETED: 'blue',
+};
+
+interface LeadStatusBadgeProps {
+ status: LeadStatus;
+}
+
+export const LeadStatusBadge = ({ status }: LeadStatusBadgeProps) => {
+ const color = leadStatusColorMap[status];
+ return (
+
+ {toTitleCase(status)}
+
+ );
+};
+
+interface CampaignStatusBadgeProps {
+ status: CampaignStatus;
+}
+
+export const CampaignStatusBadge = ({ status }: CampaignStatusBadgeProps) => {
+ const color = campaignStatusColorMap[status];
+ return (
+
+ {toTitleCase(status)}
+
+ );
+};
diff --git a/src/lib/format.ts b/src/lib/format.ts
new file mode 100644
index 0000000..d9a5e6f
--- /dev/null
+++ b/src/lib/format.ts
@@ -0,0 +1,39 @@
+// Format currency from micros to display string (INR)
+export const formatCurrency = (amountMicros: number, currency = 'INR'): string => {
+ const amount = amountMicros / 1_000_000;
+ return new Intl.NumberFormat('en-IN', { style: 'currency', currency, maximumFractionDigits: 0 }).format(amount);
+};
+
+// Format phone number for display
+export const formatPhone = (phone: { number: string; callingCode: string }): string =>
+ `${phone.callingCode} ${phone.number.replace(/(\d{5})(\d{5})/, '$1 $2')}`;
+
+// Calculate days ago from ISO date string
+export const daysAgoFromNow = (dateStr: string): number => {
+ const diff = Date.now() - new Date(dateStr).getTime();
+ return Math.floor(diff / (1000 * 60 * 60 * 24));
+};
+
+// Get aging bracket from days
+export const getAgeBracket = (days: number): 'fresh' | 'warm' | 'cold' =>
+ days < 2 ? 'fresh' : days <= 5 ? 'warm' : 'cold';
+
+// Format relative age string
+export const formatRelativeAge = (dateStr: string): string => {
+ const days = daysAgoFromNow(dateStr);
+ if (days === 0) return 'Today';
+ if (days === 1) return '1 day ago';
+ return `${days} days ago`;
+};
+
+// Format short date (Mar 15, 2:30 PM)
+export const formatShortDate = (dateStr: string): string =>
+ new Intl.DateTimeFormat('en-IN', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true }).format(new Date(dateStr));
+
+// Get initials from a name
+export const getInitials = (firstName: string, lastName: string): string =>
+ `${firstName[0] || ''}${lastName[0] || ''}`.toUpperCase();
+
+// Format large numbers (1234 -> "1.2K", 1234567 -> "1.2M")
+export const formatCompact = (n: number): string =>
+ new Intl.NumberFormat('en-IN', { notation: 'compact', maximumFractionDigits: 1 }).format(n);