Skip to content

feat(incubators): add/ update data, data structure, types, and UI components#10

Open
TarekAeb wants to merge 1 commit intoalgeria-ecosystem:mainfrom
TarekAeb:main
Open

feat(incubators): add/ update data, data structure, types, and UI components#10
TarekAeb wants to merge 1 commit intoalgeria-ecosystem:mainfrom
TarekAeb:main

Conversation

@TarekAeb
Copy link

@TarekAeb TarekAeb commented Jan 1, 2026

Description

I have:

  • Added incubators data from startup.dz website using this notebook: Notebook Link
  • Updated the incubator components to reflect the changes in the data structure
  • Updated the types to match the new data
  • Updated the filters to include the incubator type instead of year of creation

Type of Change

  • Add/Edit data
  • Bug fix
  • New feature
  • Code enhancement
  • Documentation update

Checklist

  • I have tested my changes locally
  • My code follows the project's coding style

Copilot AI review requested due to automatic review settings January 1, 2026 13:13
@netlify
Copy link

netlify bot commented Jan 1, 2026

Deploy Preview for algeria-ecosystem ready!

Name Link
🔨 Latest commit 300d9eb
🔍 Latest deploy log https://app.netlify.com/projects/algeria-ecosystem/deploys/695ccb4175adf30008dc46f1
😎 Deploy Preview https://deploy-preview-10--algeria-ecosystem.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR significantly expands the incubators feature by adding comprehensive data from startup.dz, updating the data structure to include additional fields, and enhancing the UI to display this new information.

Key Changes:

  • Expanded incubators dataset from ~10 entries to 87 entries with rich metadata including contact information, descriptions, and social media links
  • Updated data structure to replace foundedYear with incubator_type as the primary classification field, along with new optional fields for email, phone, address, and socials
  • Enhanced UI components to display new incubator information including type badges, descriptions, and multiple contact methods with appropriate icons

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/features/incubators/types.ts Updated Incubator interface to reflect new data structure with incubator_type, contact fields, and made foundedYear optional
src/shared/components/SimpleFilterBar.tsx Added type filter support and made sort functionality optional to accommodate different filtering needs
src/features/incubators/pages/Incubators.tsx Removed year-based sorting, added type filtering, and updated search to include descriptions
src/features/incubators/components/IncubatorCard.tsx Redesigned card layout to display new fields including type badge, description, social links, email, and phone with appropriate icons
src/data/incubators.json Replaced limited dataset with 87 comprehensive incubator entries scraped from startup.dz
src/data/startups.json Fixed trailing comma formatting issues
package-lock.json Version bump to 0.2.0

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +18
if (url.includes('facebook')) return <Facebook className="w-4 h-4" />;
if (url.includes('linkedin')) return <Linkedin className="w-4 h-4" />;
if (url.includes('instagram')) return <Instagram className="w-4 h-4" />;
if (url.includes('twitter')) return <Twitter className="w-4 h-4" />;
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getSocialIcon function performs case-sensitive substring matching, which may fail if URLs contain uppercase variations (e.g., "Facebook.com" or "FACEBOOK"). Consider using toLowerCase() on the URL before checking to make the matching more robust.

Suggested change
if (url.includes('facebook')) return <Facebook className="w-4 h-4" />;
if (url.includes('linkedin')) return <Linkedin className="w-4 h-4" />;
if (url.includes('instagram')) return <Instagram className="w-4 h-4" />;
if (url.includes('twitter')) return <Twitter className="w-4 h-4" />;
const normalizedUrl = url.toLowerCase();
if (normalizedUrl.includes('facebook')) return <Facebook className="w-4 h-4" />;
if (normalizedUrl.includes('linkedin')) return <Linkedin className="w-4 h-4" />;
if (normalizedUrl.includes('instagram')) return <Instagram className="w-4 h-4" />;
if (normalizedUrl.includes('twitter')) return <Twitter className="w-4 h-4" />;

Copilot uses AI. Check for mistakes.
foundedYear: number;
website?: string;
linkedin?: string;
incubator_type?: string;
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property name 'incubator_type' uses snake_case naming convention, which is inconsistent with the JavaScript/TypeScript convention of camelCase used by other properties in this interface (e.g., 'foundedYear', 'mapLocation'). Consider renaming to 'incubatorType' for consistency.

Suggested change
incubator_type?: string;
incubatorType?: string;

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +94
{incubator.socials && incubator.socials.map((social, idx) => (
<a
key={idx}
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using array index as key for map iteration is an anti-pattern when the items don't have unique identifiers. If the social links array is reordered or items are added/removed, React may incorrectly reuse components. Consider using the social URL itself as the key since it should be unique.

Suggested change
{incubator.socials && incubator.socials.map((social, idx) => (
<a
key={idx}
{incubator.socials && incubator.socials.map((social) => (
<a
key={social}

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +101
{incubator.socials && incubator.socials.map((social, idx) => (
<a
key={idx}
href={social}
target="_blank"
rel="noopener noreferrer"
className="w-8 h-8 rounded-full flex items-center justify-center text-muted-foreground hover:text-primary hover:bg-primary/5 border border-transparent hover:border-primary/20 transition-all duration-300"
>
{getSocialIcon(social)}
</a>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Social media links are missing aria-label or accessible text for screen readers. Users relying on assistive technologies won't know which social platform each icon represents. Add an aria-label attribute that describes the platform (e.g., "Visit Facebook page", "Visit LinkedIn page").

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +122
{incubator.email && (
<a
href={`mailto:${incubator.email}`}
className="w-8 h-8 rounded-full flex items-center justify-center text-muted-foreground hover:text-primary hover:bg-primary/5 border border-transparent hover:border-primary/20 transition-all duration-300"
title={incubator.email}
>
<Mail className="w-4 h-4" />
</a>
)}

{incubator.phone && (
<a
href={`tel:${incubator.phone}`}
className="w-8 h-8 rounded-full flex items-center justify-center text-muted-foreground hover:text-primary hover:bg-primary/5 border border-transparent hover:border-primary/20 transition-all duration-300"
title={incubator.phone}
>
<Phone className="w-4 h-4" />
</a>
)}
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email and phone links use the title attribute for accessibility, but title is not reliably announced by screen readers. Consider adding an aria-label attribute in addition to or instead of title to ensure the content is accessible to all users.

Copilot uses AI. Check for mistakes.
Comment on lines +752 to +753
"phone": "0661123960",
"website": "https://manque de programme d acceleration"
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The website URL appears to be invalid or contains a note in French rather than an actual website address. This should either be removed or replaced with a valid URL if one exists.

Suggested change
"phone": "0661123960",
"website": "https://manque de programme d acceleration"
"phone": "0661123960"

Copilot uses AI. Check for mistakes.
"address": "Université blida2",
"description": "حاضنة الأعمال لجامعة البليدة2 مهيكلة في شكل لجنة قيادية مشتركة تضم: ممثلين عن جامعة البليدة2، ممثلين من الوكالة لتثمين نتائج البحث العلمي واالتنمية التكنولوجية وممثل عن الشركاء الاقتصاديين. لأجل ترقية الفكر المقاولاتي في الوسط الجامعي وتعزيز روح المبادرة لدى الطلبة من أجل انشاء مشاريعهم، كما تدعم الإبداع والابتكار وتعمل على خلق تأثير حقيقي على الاقتصاد المحلي من خلال دعم الطلبة في طموحاته",
"email": "s.hadj_aissa@live.fr",
"website": "HTtPS://www.univ-blida2.dz"
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL protocol has inconsistent casing with mixed case letters in 'HTtPS'. This should be normalized to lowercase 'https' to ensure consistent URL formatting across the dataset.

Suggested change
"website": "HTtPS://www.univ-blida2.dz"
"website": "https://www.univ-blida2.dz"

Copilot uses AI. Check for mistakes.
"description": "organisme abp space créer pour aider et d’accompagner les startups sa mission principale est d’assister les porteurs du projets innovants et technologique, elle se trouve en plein centre ville de bejaia, dispose des moyens humains comme des experts, des formateurs et du materiels pour accomplir sa mission noble, de dévelloper la region et l’écosysteme économique pour accélérer le processus de devl",
"email": "LO.MOUSSOUNI@ABP-SPACE.COM",
"phone": "0660510807",
"website": "HTTPS://WWW.ABP-SPACE.COM",
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple URLs use uppercase 'HTTPS://' protocol which is inconsistent with standard URL formatting. These should be normalized to lowercase 'https://' for consistency across the dataset.

Suggested change
"website": "HTTPS://WWW.ABP-SPACE.COM",
"website": "https://WWW.ABP-SPACE.COM",

Copilot uses AI. Check for mistakes.
"description": "l’incubateur de l’ensa dispose d’un espace de coworking, de 2 salles polyvalentes d’une salle de réunion, d’un atelier de prototypage, d’un meeting room et de plusieurs bureaux individuels à la disposition des incubés. en plus des moyens mis en place par l’école (laboratoires, bibliothèques, station expérimentale, station horticole, ferme centrale et fablab)",
"email": "manal.nechar@edu.ensa.dz",
"phone": "0657936143",
"website": "HTTP://WWW.ensa.dz",
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL uses uppercase 'HTTP://WWW' which is inconsistent with standard URL formatting. This should be normalized to lowercase 'http://www' for consistency across the dataset.

Suggested change
"website": "HTTP://WWW.ensa.dz",
"website": "http://www.ensa.dz",

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +77
) : (
<></>
)}
</div>

Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty fragment serves no purpose here. Consider either removing the else clause entirely or using null instead of an empty fragment.

Suggested change
) : (
<></>
)}
</div>
) : null}
</div>

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@Fcmam5 Fcmam5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @HouariZegai for pitching in...

But I think that this PR introduces a lot of changes at once, they should be double checked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be safer and cleaner to have a sorting logic. Either we append new entries to the list or we have them sorted alphabetically or by date they were founded

"incubator_type": "Incubateurs universitaires",
"address": "Cité 50 lgts B6 N°2 Oued Merzoug Tipaza",
"email": "amerouane.lmd@cu-tipaza.dz",
"phone": "0666810772"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such entries are incosistent, some have country code while this one doesn't.

For email addresses, it's a bit questionable to have a personal email address instead of an institution's official one.

Additionally, such a contribution removes foundedYear information and mapLocation which is sad :(

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve unified the phone numbers; the corrected version will be included in the next commit.
As for the email addresses, I don’t see an issue, those emails are the ones listed on the university’s website for contacting the incubator director or the responsible person as well as the startup.dz website.

"city": "Algiers",
"mapLocation": "https://maps.app.goo.gl/EhQwwiGx64Zee6kt8"
"name": "ALSTRATO",
"incubator_type": "Incubateurs privés",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more robust to use an enum instead of a magic string.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum in json ???

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could either do it with id/relashionships as it's done in media and media categories e.g https://github.com/algeria-ecosystem/ecosystem/blob/main/src/data/media_category.json

Or define a JSON schema and have this field marked as enums and force users to use one of the pre-defined values

"city": "Algiers"
"name": "ENSM INCUBATOR",
"incubator_type": "Incubateurs universitaires",
"address": "المدرسة الوطنية العليا للمناجمنت القطب الجامعي بالقليعة",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think that entries should be in one language: English.

And if the main maintainer and/or the community wants to have l10n, we have an approach to handle it, but mixing languages here is odd imo

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have modified that

const faviconUrl = domain ? `https://fetchfavicon.com/i/${domain}?size=64` : '';


const getSocialIcon = (url: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many clean ways to handle such logic, having a Map, a Switch case..

"linkedin": "https://linkedin.com/company/crearena",
"city": "Blida"
"name": "UTINC4.2",
"incubator_type": "university",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. For incubator_type, we can use camelCase.
  2. For other new fields, let’s stick to the currently available ones and avoid introducing new fields to the entity.
  3. We should keep the existing data and avoid removing any of it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that I can’t collect the foundedYear attribute for all incubators because it’s not available on either startup.dz or the universities’ websites.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make it optional then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants