Skip to main content

Overview

The Services Directory is the flagship feature of Dzaleka Online Services, connecting over 100+ verified organizations with community members seeking healthcare, education, legal support, and business services. It provides a searchable, categorized database of active service providers operating in and around Dzaleka Refugee Camp.
The Services Directory is built using Astro’s content collections, allowing easy content management through Markdown files with frontmatter validation.

User Experience

Users can discover services through multiple pathways:
1

Browse by Category

Filter services by categories like Education, Health, Non-profit Organizations, Advocacy, Humanitarian Aid, Entrepreneurship, Youth, and Cultural services.
2

Search by Keyword

Real-time search functionality filters services by title as users type.
3

View Featured Services

Highlighted services appear prominently with verified badges.
4

Pagination

Browse through services with 6 items per page for optimal viewing.

Service Detail Pages

Each service has a dedicated page showing:
  • Organization details: Title, description, logo, category
  • Contact information: Email, phone, operating hours
  • Location: Address with interactive map coordinates
  • Social media: Links to Facebook, Twitter, Instagram, LinkedIn, website
  • Verification status: Verified badge for trusted organizations
  • Last updated date: Shows when information was refreshed

Real-time Filtering

Client-side JavaScript filters services instantly without page reloads

SEO Optimized

Rich metadata and structured data (Schema.org) for search engines

Mobile Responsive

Adaptive design works seamlessly on phones, tablets, and desktops

100% Free

Organizations can register and list their services at no cost

Content Schema

Services are stored as Markdown files in src/content/services/ with YAML frontmatter. Here’s the schema:
title: "Organization Name"          # Required
category: "Education"               # Required - predefined categories
description: "Brief overview"       # Required
status: "active"                    # active | inactive | pending
location:
  address: "Physical address"
  city: "Lilongwe"
  coordinates:
    lat: -13.6628274
    lng: 33.8704301
contact:
  email: "info@organization.org"
  phone: "+265 123 456 789"
  hours: "Monday-Friday, 8:00 AM - 5:00 PM"
socialMedia:
  facebook: "https://facebook.com/page"
  twitter: "https://twitter.com/handle"
  instagram: "https://instagram.com/handle"
  linkedin: "https://linkedin.com/company/name"
  website: "https://website.com"
logo: "https://example.com/logo.png" # Image URL
featured: true                       # Boolean - shows on homepage
verified: true                       # Boolean - shows verified badge
lastUpdated: 2024-12-24             # Date in YYYY-MM-DD format

Real Example from Source

Here’s a real service from the codebase (tumaini-letu.md):
title: Tumaini Letu
category: "Cultural & Arts"
description: Cultural events and festivals promoting refugee talents and cultural exchange.
location:
  address: Tumaini Letu P.O.Box 1459
  city: Lilongwe
  coordinates:
    lat: -13.6628274
    lng: 33.8704301
contact:
  email: 'Info@tumainiletu.org'
  phone: '+265993380983'
  hours: 'Monday-Friday, 8:00 AM - 5:00 PM'
socialMedia:
  facebook: 'https://www.facebook.com/tumaini.malawi/'
  twitter: 'https://twitter.com/TumainiLetuMW'
  instagram: 'https://www.instagram.com/tumaini_letu_mw/'
  linkedin: 'https://www.linkedin.com/company/tumaini-letu/'
  website: 'https://tumainiletu.org/'
logo: 'https://tumainiletu.org/wp-content/uploads/2021/07/LOGO-tumaini-letu-TEXT-COLOR-png.png'
featured: false
verified: true
status: "active"
lastUpdated: 2024-12-24

How to Add a New Service

1

Create Markdown File

Create a new .md file in src/content/services/ with a URL-friendly filename:
touch src/content/services/new-organization.md
2

Add Frontmatter

Copy the schema template above and fill in your organization’s details:
---
title: "New Organization Name"
category: "Health"
description: "Provides healthcare services..."
status: "active"
contact:
  email: "contact@org.com"
  phone: "+265 XXX XXX XXX"
verified: true
lastUpdated: 2025-03-09
---
3

Add Description (Optional)

Below the frontmatter, add detailed markdown content:
## About Our Organization

Detailed description of services, history, and impact...

### Programs Offered
- Program 1
- Program 2
4

Test Locally

Run the development server to preview:
npm run dev
Navigate to /services to see your new listing.

User Registration Flow

Organizations can self-register through the /services/register page:
  1. Form Submission: Fill out organization details via web form
  2. Email Notification: Submission details sent to admin team
  3. Review Process: Admin verifies information and creates content file
  4. Publication: Service goes live after approval
  5. Confirmation: Organization receives success notification at /services/update-success

Technical Implementation

Data Fetching

Services are fetched using Astro’s Content Collections API:
src/pages/services/index.astro
import { getCollection } from 'astro:content';

// Get all services
const allServices = await getCollection('services');

// Filter and sort
const sortedServices = sortServices(allServices, 'featured');

Search & Filter Logic

Client-side filtering uses vanilla JavaScript for performance:
Interactive Filtering
function filterServices() {
  let visibleCount = 0;
  
  serviceCards.forEach(card => {
    const title = card.dataset.title;
    const category = card.dataset.category;
    const matchesSearch = !searchTerm || title.includes(searchTerm.toLowerCase());
    const matchesCategory = !categoryFilter || category === categoryFilter;
    
    if (matchesSearch && matchesCategory) {
      card.style.display = 'block';
      visibleCount++;
    } else {
      card.style.display = 'none';
    }
  });
}

Category Routing

Dynamic routes handle category filtering (/services/category/[category]):
src/pages/services/category/[category]/[...page].astro
export async function getStaticPaths({ paginate }) {
  const allServices = await getCollection('services');
  
  // Group services by category
  const categories = [...new Set(allServices.map(s => s.data.category))];
  
  return categories.flatMap(category => {
    const categoryServices = allServices.filter(
      service => service.data.category === category
    );
    return paginate(categoryServices, { params: { category }, pageSize: 6 });
  });
}

SEO & Structured Data

The services directory includes comprehensive SEO:
{
  "@context": "https://schema.org",
  "@type": "ItemList",
  "name": "Dzaleka Services Directory",
  "description": "Verified services in Dzaleka Refugee Camp",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "url": "https://services.dzaleka.com/services/tumaini-letu",
      "name": "Tumaini Letu"
    }
  ]
}
<meta property="og:title" content="Services Directory - Dzaleka Online Services" />
<meta property="og:description" content="Connect with 100+ verified organizations..." />
<meta property="og:image" content="/images/services-directory.jpg" />
<meta property="og:type" content="website" />

Statistics & Analytics

The platform tracks key metrics:
src/utils/serviceStats.ts
export function calculateServiceStats(services) {
  return {
    total: services.length,
    active: services.filter(s => s.data.status === 'active').length,
    verified: services.filter(s => s.data.verified).length,
    byCategory: services.reduce((acc, service) => {
      acc[service.data.category] = (acc[service.data.category] || 0) + 1;
      return acc;
    }, {})
  };
}
View stats at /services/stats for real-time insights.

Best Practices

Keep Information Current

Update the lastUpdated field whenever details change. Users rely on accurate contact info.

Use High-Quality Logos

Recommended size: 400x400px, PNG format with transparent background.

Write Clear Descriptions

Explain what services you offer, who you serve, and how to access your programs.

Verify Contact Details

Ensure phone numbers and emails are monitored and responsive.

Common Issues & Solutions

  1. Check that status: "active" is set in frontmatter
  2. Verify the file is in src/content/services/ directory
  3. Ensure frontmatter follows the correct YAML syntax (proper indentation)
  4. Restart the dev server: npm run dev
The search function filters by title only. Ensure your service title contains relevant keywords users might search for.
Use decimal degrees format:
coordinates:
  lat: -13.6628274  # Latitude (negative for South)
  lng: 33.8704301   # Longitude (positive for East)