News Portal is a comprehensive, bilingual (Bangla/English) news portal built with modern web technologies. It serves as both a public-facing news website and a full-featured admin dashboard for journalists, editors, and administrators to manage news content, videos, categories, and user roles.
GitHub: newsportal website
Type: Next.js 15 App Router application with TypeScript
License: ISC
🛠️ Tech Stack
| LayerTechnology |
| Framework | Next.js 15.x (App Router) |
| UI Library | React 19.x |
| Language | TypeScript (strict mode) |
| Styling | Tailwind CSS v4.1 + Custom CSS |
| UI Components | Radix UI primitives + custom shadcn-style components |
| Icons | Lucide React |
| State Management | React hooks (useState, useEffect, useCallback, useRef) |
| Data Fetching | Axios with interceptors |
| Carousel | Embla Carousel (React) |
| Charts | Recharts |
| Notifications | Sonner (toast) |
| YouTube | @next/third-parties |
📁 Directory Structure
src/
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout (SEO, GA, schema.org)
│ ├── page.tsx # Home page (skeleton wrapper)
│ ├── (root)/ # Grouped routes (public site)
│ │ ├── layout.tsx # Public layout with HomeLayout
│ │ ├── page.tsx # HomePage component
│ │ ├── _components/ # Home page sections
│ │ │ ├── HomeLayout.tsx # Header+Footer wrapp
│ │ │ └── ...
│ │ ├── news/ # News routes
│ │ │ ├── page.tsx # Redirects to all-news
│ │ │ └── ...
│ │ ├── videos/ # Video listing
│ │ ├── about-us/, contact/, advertising/, etc.
│ │ └── sitemap.xml, rss.xml, robots.ts # SEO routes
│ └── admin/ # Admin panel routes
│ ├── login/page.tsx # Admin login
│ └── dashboard/
│ ├── layout.tsx # Dashboard sidebar wrapper
│ ├── page.tsx # Dashboard overview
│ ├── news/ # News management (super_admin)
│ ├── categories/ # Category management
│ ├── review-reports/ # Editor review queue
│ ├── my-reports/ # Reporter's own articles
│ ├── manage-editorial/ # User management (super_admin)
│ ├── bulletins/ # Breaking news bulletins
│ └── videos/ # Video management
├── components/ # Reusable components
│ ├── ui/ # Radix-based primitives
│ │ ├── button.tsx, badge.tsx, alert.tsx
│ │ ├── dialog.tsx, select.tsx, table.tsx
│ │ ├── carousel.tsx, .tsx, skeleton.tsx
│ │ └── navigation-menu.tsx, tooltip.tsx
│ ├── layouts/ # Layout components
│ │ ├── Header.tsx # Sticky header with nav
│ │ ├── Footer.tsx # Site footer
│ │ ├── TopNews.tsx # Breaking news ticker
│ │ └── BackToTopButton.tsx
│ ├── dashboard/ # Admin dashboard components
│ │ ├── DashboardSidebar.tsx # Role-based navigation
│ │ ├── DashboardPage.tsx # Stats overview
│ │ ├── NewsTable.tsx # CRUD table with modals
│ │ ├── CategoriesPage.tsx # Category management
│ │ └── Add/Edit news dialogues
│ └── pages/ # Full page components
│ ├── PublicNewsDetailsPage.tsx
│ ├── AllPublicVideosPage.tsx
│ ├── AllBangladeshNews.tsx
│ └── ...
│ ├── map/ # Election map
│ │ ├── BangladeshElectionMap.tsx (SVG interactive)
│ │ ├── MapDistrictLabels.tsx
│ │ └── ElectionResultsTable.tsx
│ ├── category_based_news/
│ │ └── SectionLayout.tsx # Reusable news section
│ ├── header/
│ │ └── BreakingNews.tsx # Scrolling ticker
│ ├── NewsCard.tsx, VideoCard.tsx, CategoryBadge.tsx
│ ├── ShareButton.tsx, ShareIcon.tsx
│ ├── InfiniteNewsArticleLoader.tsx # Infinite scroll
│ ├── RamadanSVG.tsx, ArchiveSVG.tsx, etc.
│ └── ...
├── lib/ # Utilities & API layer
│ ├── api.ts # Axios instance + all endpoints
│ ├── auth.ts # Auth helpers (localStorage+cookies)
│ ├── buildNewsLink.ts # SEO-friendly URL builder
│ ├── buildVideoLink.ts
│ ├── categoryPills.tsx # Homepage filter pills
│ ├── categoryPillsData.ts
│ ├── staticCategories.ts # Fallback nav categories
│ ├── youtubeUtils.ts # YouTube ID extraction
│ ├── formData.ts # Date formatting
│ ├── utils.ts # cn() utility
│ ├── manifestos.ts # Party manifestos data
│ ├── voterStats.ts # Election statistics
│ └── ...
├── types/ # TypeScript interfaces
│ ├── index.ts # Barrel export
│ ├── news.ts # NewsItem, NewsResponse
│ ├── videos.ts # Video interface
│ ├── category.ts # Category interface
│ ├── user.ts # UserData, UserRole
│ ├── ramadan.ts # RamadanData
│ ├── bulletin.ts # Bulletin types
│ ├── api.ts # API response types
│ ├── party.ts # Political party types
│ └── bangladesh-map.ts # Map data types
├── data/ # Static data files
│ ├── party_data.ts # Election party data
│ ├── map_path_data.ts # SVG map coordinates
│ ├── area_map_to_seat.ts # District mapping
│ ├── editorial_info.ts
│ ├── contact_info.ts
│ ├── bd_divisions.ts, bd_district.ts, bd_upazilas.ts
│ └── ...
├── hooks/ # Custom React hooks
│ ├── useCountdown.ts # Timer hook
│ └── use-mobile.ts # Mobile detection
├── middleware.ts # Next.js middleware (auth + redirects)
└── next.config.js # Next configuration
├── CSP headers (Google Analytics, Tag Manager)
├── Image remote patterns
├── Redirects (www to non-www)
└── Cache headers
🏗️ Architecture & Routing
App Router Structure
The application uses Next.js 15 App Router with route groups:
/(root) → Public-facing website (grouped for layout isolation)/admin → Admin panel (protected by middleware)- API routes →
/api/* (not shown in visible files; backend likely separate)
Route Pattern for News Articles
/news/[category]/[slug] → Dynamic article pages
├── Example: /news/category/slug
├── `buildNewsLink(id, title, category)` generates paths
└── Middleware redirects old `/news/id/title` → new format
Middleware Protection (middleware.ts)
- Role-based access control for admin routes
- News redirect: Old
/news/123/title → /news/category/title-123 - Protected routes:
/admin/* requires token + role in cookies - Role hierarchy:
super_admin → full accesseditor → review-reports, my-reports, bulletins, videosreporter → my-reports only
Access Matrix:
| RouteAllowed Roles |
/admin/dashboard/manage-editorial | super_admin |
/admin/dashboard/news | super_admin |
/admin/dashboard/categories | super_admin |
/admin/dashboard/review-reports | super_admin, editor |
/admin/dashboard/my-reports | super_admin, editor, reporter |
/admin/dashboard/bulletins | super_admin, editor |
/admin/dashboard | all authenticated |
🔐 Authentication & Authorization
Storage Strategy:
- localStorage → token, userData, role (client-side)
- Cookies → token, role (middleware SSR access)
Auth Flow (lib/auth.ts):
- Login → API returns
{ token, userData, role } setAuthData() stores in both localStorage and cookies- Middleware reads cookies for route protection
- Role-based sidebar renders filtered navigation items
- Token automatically attached via Axios interceptor
- 401 responses trigger logout + redirect
📡 API Layer (lib/api.ts)
Axios instances:
api (auth interceptors, no-cache headers) → authenticated requestscachedApi (no interceptors) → public static data
API Modules:
| ModulePurposeAuth Required |
authApi.login() | Admin login | No |
newsApi.* | CRUD, featured, popular, search | Yes |
reporterNewsApi.* | Reporter-scoped news | Yes (reporter+) |
editorNewsApi.* | Editor review/update | Yes (editor+) |
categoryApi.* | Category CRUD | Yes (super_admin) |
bulletinApi.* | Breaking bulletins | Yes (editor+) |
videoApi.* | Admin video CRUD | Yes |
publicVideoApi.* | Public video listing | No |
userApi.* | User CRUD | Yes (super_admin) |
ramadanApi.* | Prayer times, calendar | No |
partyApi.* | Election parties | No |
manifestoCommentApi.* | Comments on manifestos | No |
pollCommentApi.* | Election poll comments | No |
News API Query Params (example):
/news/all-news?sortBy=createdAt&limit=4&search=something
&subCategory=mySubCat&category=myCat
&page=1&orderBy=asc
🎨 Components & Design System
Layout Components
| ComponentRole |
HomeLayout | Wraps public pages: <Header /><main /><Footer /><TopNews /><BackToTopButton /> |
Header | Sticky: logo + search + date + nav bar + category pills + BreakingNews ticker |
Footer | Site links, contact, copyright |
DashboardSidebar | Collapsible sidebar with role-based menu + user info + logout |
Header Component (components/layouts/Header.tsx)
Two-row design:
- Top bar: Logo (left), search (center), date/Live TV (right), mobile menu toggle
- Category pills row: Horizontal scroll pill navigation (
categoryPills array) → filters content - Main nav: Black background, 8 visible items max, "আরও" dropdown for overflow
- Breaking news ticker (
BreakingNews.tsx) below nav - Mobile: Hamburger menu → full-screen overlay with accordion subcategories
State Management:
categoryLoading → fetches categories from API, falls back to staticCategoriesexpandedCategory → mobile submenu stateactivePill → tracks current filter
UI Components (shadcn-style)
Radix UI primitives wrapped with Tailwind:
Button, Badge, Alert, Input, Select, Dialog, Table, Carousel, Skeleton, Tooltip, NavigationMenu
🏠 Homepage Architecture (app/(root)/_components/HomePage.tsx)
Layout pattern:
<div className="max-w-7xl mx-auto bg-gray-50">
<div className="flex flex-col lg:flex-row gap-6 py-6">
{/* Left: News Grid (2/3 width) */}
<div className="flex-1 lg:w-2/3">
<FeaturedNewsSlider /> {/* Large hero + 6 thumbnails */}
<SectionLayout title="My title 1" category="My Category 1" columns={2} count={4} />
<SectionLayout title="My title 2" category="My Category 2" columns={4} count={8} />
{/* More sections... */}
</div>
{/* Right: Sidebar (1/3 width) */}
<div className="lg:w-1/3 flex flex-col">
<RamadanTimer2 />
<EidBanner />
<AdsForCall />
<NewsTitles />
<AdsSpace_300x250 />
<VideoNewsSection />
<AdsSpace_300x400 />
<PopularNews />
<AdsSpace_300x400 />
</div>
</div>
{/* Full-width bottom sections */}
<SectionLayout title="Title" category="Category" columns={5} count={10} />
{/* ... more categories ... */}
<AllNewsContentShort /> {/* Additional news grid */}
</div>
SectionLayout (components/category_based_news/SectionLayout.tsx)
Reusable component that:
- Fetches news by category/subCategory
- Renders grid of
NewsCard components (3–5 columns responsive) - Shows "Load More" button or infinite scroll (depending on config)
- Displays section title with category badge
📰 News Components
NewsCard (components/NewsCard.tsx)
Props: item: NewsItem, index: number
Features:
- Image (lazy-loaded, optimized with Next.js
Image) - Category + subcategory badges
- Title (line-clamp-2), description (line-clamp-3)
- Relative timestamp ("এইমাত্র", "X মিনিট আগে")
- Link:
buildNewsLink(item.id, item.title, item.category)
PublicNewsDetailsPage (app/(root)/_components/pages/PublicNewsDetailsPage.tsx)
Full article view:
- Hero image + title + metadata (author, date, category)
- Article body (description)
- Social share buttons (Facebook, Twitter, WhatsApp, Copy Link)
- Related videos (3 from same category)
- Related news (4 from same category)
- Sticky sidebar? (depends on design)
InfiniteNewsArticleLoader (components/InfiniteNewsArticleLoader.tsx)
Infinite scroll implementation:
- Initial load: main article + 3 related articles
- Load more: fetches 2 articles at a time using rotating sort modes (views desc, createdAt desc, views asc, createdAt asc)
- Uses Intersection Observer on a trigger element at the bottom
- Prevents duplicates with
loadedIdsRef Set - Cycles through pages of each sort mode before exhausting all content
🗂️ Category System
Two-tier categories:
- Static categories (
lib/staticCategories.ts) → Always displayed in nav (fallback) - Dynamic categories (from API) → fetched on Header mount, merged with static
Category pills (below header):
- Defined in
lib/categoryPillsData.ts + lib/categoryPills.tsx - Special pills:
latest, all-news, all-bangladesh, video, archive, book-fair, ramadan, election - Active state highlighting
- Some pills have custom SVG icons (Ramadan, Book, Ballot, Map, Video)
Category filtering:
- Pills route to
/?filter=pillId or direct /news/all-news?category=... - Dropdown subcategories route to
?subCategory=X&category=Y
🗳️ Election Features
Bangladesh Election Map (components/map/BangladeshElectionMap.tsx)
Interactive SVG map of Bangladesh parliamentary constituencies:
- Zoom/Pan: Mouse wheel (desktop), pinch (mobile), double-tap reset
- Touch support: Drag when zoomed, gestures for mobile
- Color coding: Each constituency colored by winning party (from
partyData) - Tooltip: Shows constituency number, district name, winning party
- Responsive: Two-column layout on desktop (results table + map), stacked on mobile
- Data sources:
data/map_path_data.ts → SVG path data for each areadata/party_data.ts → party colors + winArea[] arraysdata/area_map_to_seat.ts → area ID → district name mapping
Manifestos (app/(root)/manifesto/)
Data (lib/manifestos.ts):
- Party-wise manifestos (BNP, Jamaat, NCP, Islami Andolon)
- Each has
partyId, flag/logo, name, englishName, slug, manifesto[] array
Pages:
/manifesto → lists all parties with collapsible manifesto points/manifesto/[party] → individual party manifesto with comment section
Comment APIs: manifestoCommentApi → add/get comments per party (user-attributed)
🌙 Ramadan Timer (app/(root)/ramadan/)
RamadanTimer2 component (_components/RamadanTimer2.tsx):
- Swipeable card (prayer times ↔ iftar/sehri)
- Fetches data from
ramadanApi.getTodayData() - Displays 5 prayer times (Fajr, Dhuhr, Asr, Maghrib, Isha) with +2 min adjustment
- Shows Sehri (pre-dawn) and Iftar (sunset) times
- Auto-rotates every 10 seconds
- Manual swipe/drag interaction
- Bengali numerals
API (lib/api.ts → ramadanApi):
getTodayData(city, country)getByDate(date, city, country)getMonthlyCalendar(year, month, city, country)getHijriCalendar(hijriYear, hijriMonth, city, country)getRamadanCalendar(hijriYear, city, country)
🎥 Videos System
Public video page: /videos → AllPublicVideosPage
- Grid/List of videos (YouTube embeds or direct)
VideoCard component with:- YouTube thumbnail auto-generation (
youtubeUtils.ts) - Play button overlay
- Category badge
- Title + date
publicVideoApi.getAll() + pagination/filtering
Admin video management:
/admin/dashboard/videos → CRUD (super_admin, editor, reporter)videoApi for admin operations- Validates YouTube URLs
🗃️ News Data Model (types/news.ts)
interface NewsItem {
id: number
title: string
description: string
category: string
subCategory: string | null
imageUrl: string
status: "draft" | "published" | "archived"
createdAt: string
updatedAt?: string
views: number
isBreakingNews?: number // 0/1 flag
isFeatured?: number // 0/1 flag
featurePriority?: number // For ordering featured
featureExpireAt?: string // Timestamp
location?: {
division: string
district: string
upazila: string
}
authorName?: string | null
authorId: number
author: User
tags?: string[]
keywords?: string[]
scheduledTime?: string | null // For scheduled publishing
}
🎛️ Admin Dashboard (app/admin/dashboard/)
DashboardSidebar (components/dashboard/DashboardSidebar.tsx)
Role-based navigation items:
- Dashboard (all)
- Manage Editorial (super_admin only)
- Bulletins (super_admin, editor)
- News (super_admin only)
- Categories (super_admin only)
- Review Reports (super_admin, editor)
- Videos (all)
- My Reports (super_admin, editor, reporter)
Each item shows icon + label, active state highlighting.
News Management (NewsTable.tsx)
Features:
- Table view with pagination (10 per page)
- Filters: category dropdown
- Columns: #, Image, Title, Category, Status, Breaking, Featured, Priority, Expire At, Author, Reporter, Created At, Actions
- Row expansion: Click to highlight
- Actions: Edit (dialog), Delete (confirm dialog)
- Breaking news toggle: Button toggles
isBreakingNews - Add News modal: Full form with image upload preview, tags/keywords (Enter to add), location selectors (division → district → upazila cascading), checkboxes for breaking/featured
- Edit News modal: Similar, only sends changed fields
- Image preview: FileReader base64 preview before upload
- Loading states: Skeleton rows
- Alerts: Success/error toasts (Sonner)
Form fields:
- Required: title, description, category, image
- Optional: authorName, subCategory, location, isBreakingNews, isFeatured, featurePriority, featureExpireAt, tags, keywords
🏢 Organization Schema (SEO)
Root layout (app/layout.tsx) embeds:
- Organization schema (Organization + WebSite)
- Google Analytics (lazy-loaded)
- Social meta (OpenGraph, Twitter)
- Preconnects to Google storage & GTM
🎯 Key Utilities
URL Builders
lib/buildNewsLink.ts:
buildNewsLink(id, title, category?)
// → /news/category/title-slug-id OR /news/title-slug-id
Slug: Bangla title → lowercase, spaces→dashes, remove special chars.
lib/buildVideoLink.ts:
buildVideoLink(videoId, title?)
// → /videos/[id]/[slug]
Date Formatting (lib/formData.ts)
formatDate() → "20 Mar 2026, 10:30 AM" (English)
Bangla number conversion used throughout Header and timers.
YouTube Utils (lib/youtubeUtils.ts)
extractYouTubeInfo(url) → extracts video ID from various URL formatsgetYouTubeThumbnail(videoId) → returns img.youtube.com/vi/[id]/hqdefault.jpg
🗺️ Bangladesh Geographic Data (data/)
bd_divisions.ts → Division names ( sylhet, dhaka, chittagong, etc.)bd_district.ts → Districts with division_id linkagebd_upazilas.ts → Upazilas linked to districtsarea_map_to_seat.ts → Map constituency IDs to human-readable namesmap_path_data.ts → SVG path/polygon definitions for each constituency
Used in:
- News filtering by location
- Election map rendering
- News creation forms (cascading selects)
📱 Responsive Design
- Mobile-first approach with Tailwind breakpoints (sm, md, lg, xl)
- Header:
- Desktop: Full nav + dropdowns
- Mobile: Hamburger → overlay with accordion submenus
- Election map:
- Touch gestures (pinch zoom, drag)
- Different zoom controls layout per breakpoint
- Tooltips positioned to avoid viewport edges
- News cards: 1 col mobile → 2 col md → 3-5 col lg depending on section
- Sidebar: Hidden on mobile, fixed left desktop (64w)
⚡ Performance Optimizations
- Image optimization:
- Next.js
Image with loading="lazy" (except first/large hero with priority) quality={40} for thumbnailsfill + object-cover for responsive containers- Code splitting:
- Dynamic imports for heavy components (e.g.,
EidBanner conditionally loaded) Suspense boundaries on root page- Caching:
cachedApi for categories (no-auth, no-cache disabled)- Static data in
data/ files cache() wrapper for news details fetch- Infinite scroll reduces initial bundle, loads on demand.
- Third-party scripts (GA, GTM) lazy-loaded with
strategy="lazyOnload"
🔍 SEO & Metadata
Each route exports metadata (Next.js Metadata API):
- Dynamic title templates:
%s | News title - OpenGraph (images, title, description, locale
bn_BD) - Twitter cards (summary_large_image)
- Canonical URLs with alternates
- ** robots** (index/follow)
- Structured data (
application/ld+json) for: - Organization (with logo, social links)
- WebSite (SearchAction)
- NewsArticle (on article pages)
Sitemaps (dynamic):
/sitemap.xml → routes/news-sitemap-1.xml → news URLs/video-sitemap.xml/category-pages-sitemap.xml/static-pages-sitemap.xml
RSS feed: /rss.xml route
🧪 Type Safety
- TypeScript strict mode (
tsconfig.json) - Comprehensive types in
types/ directory - API responses typed (though some
any remain in legacy components) - No
@ts-ignore scattered (mostly clean)
🎯 Notable Features
- Breaking News Bulletins (
BulletinTable) → Quick push to top of site - Featured News Rotation →
featurePriority, featureExpireAt for time-bound highlights - News Scheduling →
scheduledTime for future publish - Search → Global search bar →
/news/all-news?search=query - Social Sharing → Share buttons per article (Facebook, Twitter/X, WhatsApp, Copy)
- Infinite Scroll → article feed loads more indefinitely
- Election Map → Interactive SVG with zoom/pan/tooltip
- Ramadan Timer → Prayer/sehri/iftar times with swipe card
- Multi-language → Bangla numerals, Bangla date formatting, Bangla UI
- Commenting → on manifestos and polls (anonymous via hash or authenticated)
🚀 Getting Started
npm install # Install dependencies
npm run dev # Development at http://localhost:3000
npm run build # Production build
npm run start # Start production server
npm run lint # ESLint check
Environment variables:
NEXT_PUBLIC_API_BASE_URL → Backend API endpointNEXT_PUBLIC_BASE_URL → Site canonical URL
📊 Data Flow Summary
Client Request (e.g., /news/রাজনীতি/Title-123)
↓
Middleware
├─ Redirect old-style news URLs
└─ Check /admin auth (cookies)
↓
Next.js Route Handler (Server Component)
├─ Extract news ID from slug
├─ Fetch article details (cached)
├─ Generate metadata (SEO)
└─ Render page
↓
Client Component (PublicNewsDetailsPage)
├─ Display article
├─ Fetch related videos + news (parallel)
└─ Render share buttons
🧩 Dependencies
Core: next, react, react-dom, typescript
Styling: tailwindcss, clsx, tailwind-merge, tailwindcss-animate, autoprefixer, postcss
UI: @radix-ui/*, lucide-react, sonner, class-variance-authority
Utilities: axios, embla-carousel-react, recharts
Third-party: @next/third-parties (for YouTube embeds, etc.)
🎓 Best Practices Observed
- ✅ App Router with Server/Client component separation
- ✅ TypeScript strict with proper typing
- ✅ Component composition (small reusable pieces)
- ✅ Error boundaries (Next.js error.tsx files present)
- ✅ Loading states (loading.tsx + skeleton components)
- ✅ SEO-friendly (metadata, sitemaps, RSS, structured data)
- ✅ Accessibility (ARIA labels, keyboard navigation in dropdowns)
- ✅ Responsive (mobile-first Tailwind)
- ✅ Performance (image optimization, lazy loading, caching)
- ✅ Security (CSP headers, XSS protection, no eval)
This codebase represents a production-grade news portal with a full editorial workflow (reporter → editor → publisher), role-based access control, rich media support, and Bangladesh-focused features (election mapping, Bangla numerals, Ramadan times).