<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: devhabeeb</title>
    <description>The latest articles on DEV Community by devhabeeb (@devhabeeblateef).</description>
    <link>https://dev.to/devhabeeblateef</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F955308%2F55e28b51-ef20-4e47-8be8-14baa7eeb792.png</url>
      <title>DEV Community: devhabeeb</title>
      <link>https://dev.to/devhabeeblateef</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devhabeeblateef"/>
    <language>en</language>
    <item>
      <title>Uber’s 12-Year Ride Ends with a Whisper</title>
      <dc:creator>devhabeeb</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:27:44 +0000</pubDate>
      <link>https://dev.to/devhabeeblateef/ubers-12-year-ride-ends-with-a-whisper-8b1</link>
      <guid>https://dev.to/devhabeeblateef/ubers-12-year-ride-ends-with-a-whisper-8b1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyc7yzbty1zr3z8vsxtom.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyc7yzbty1zr3z8vsxtom.webp" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
On September 2, 2026, Uber hit the eject button on its Nigerian (and Ugandan) ride-hailing operations. After launching in Lagos way back in 2014 and spending over a decade ferrying ninjas through traffic jams, potholes, and “I’m five minutes away” lies, the company sent a polite but brutal message:&lt;/p&gt;

&lt;p&gt;After a thorough review of our business, we have made the tough decision to wind down our operations in Nigeria, effective 2 September 2026.&lt;br&gt;
Boom. App dead. Drivers stranded mid-trip in some cases (the “Uber rapture,” as Twitter ninjas dubbed it). Help center stays open till September 23 for loose ends, then silence.&lt;/p&gt;

&lt;p&gt;This wasn’t some random FAAN airport ban revenge plot (Uber clarified that explicitly). It was part of a bigger global restructuring: ~3,300 jobs cut worldwide (about 10% of the workforce), focus shifting hard toward autonomous vehicles/robotaxis, and streamlining to markets where the numbers still slap. Nigeria’s intense competition (Bolt, inDrive, and a graveyard of 2,500+ failed apps), sky-high fuel costs post-subsidy removal, inflation, currency chaos, and driver economics made the ride-hailing math stop adding up for the big dogs.&lt;/p&gt;

&lt;p&gt;Uber now only rolls in Egypt, Ghana, Kenya, and South Africa on the continent. Four markets. From the early days of dominating Lagos to ghosting the biggest population prize in Africa. Ruthless efficiency, ninja-style.&lt;/p&gt;

&lt;p&gt;They Bought Glovo (via Delivery Hero)&lt;br&gt;
Here’s where the shadows get thicker, Code Ninjas. While Uber was vanishing from the roads, it was already deep in a massive $14.8 billion (equity value) deal to acquire Delivery Hero (the German parent of Glovo), announced back in July 2026.&lt;/p&gt;

&lt;p&gt;Glovo’s African ops (Nigeria, Kenya, Uganda, Côte d’Ivoire, Morocco, Tunisia) are staying with Uber in the deal. European overlapping bits got carved out and sold separately to avoid antitrust headaches. Closing expected in the second half of 2027, pending approvals.&lt;/p&gt;

&lt;p&gt;So Uber left the people-moving business… and is buying the parcel-and-jollof-moving business. Glovo has been crushing it as a delivery player in Nigeria (fastest-growing market for them in 2025, per reports). Uber is essentially swapping cars for bikes and bags: less organized driver strikes, cheaper last-mile labor, more food, groceries, and pharmacy runs. As one sharp analysis put it, they’re shedding the model where drivers learned to protest and keeping the one built on high-volume, low-friction delivery.&lt;/p&gt;

&lt;p&gt;Naija no be easy market to fully leave, as the timelines predicted.&lt;/p&gt;

&lt;p&gt;What the Streets (and X) Are Saying&lt;br&gt;
The X dojo exploded, as expected. Verified vibes from the timeline:&lt;/p&gt;

&lt;p&gt;The “front door / kitchen door” take: “Uber is ‘leaving Nigeria’ by the front door while potentially buying its way back in through the kitchen. Naija no be easy market to leave!” pure gold, and accurate.&lt;br&gt;
Political spice and fact-checks flew: Debates over whether “Glovo Nigeria is a Nigerian company” (technically a local operating entity under the group), with some officials getting roasted for oversimplifying the $14.8B global deal as a pure Nigeria love story. One post called out the complexity cleanly: Glovo Spain bits are being sold off; Glovo Nigeria stays in the Uber bag.&lt;br&gt;
Driver nostalgia and shade: Screenshots of weekly earnings flexes mixed with “Uber leaving means WHAT exactly?” and jokes about the roads chasing them out more than any government. Some mourned the reliability; others shrugged that Bolt and inDrive are already filling the vacuum hard.&lt;br&gt;
Broader chaos energy: “Nigeria right now: Dangote going public… Uber has left… 2027 politics warming up. And somehow we’re expected to act like September is just another month.” Classic Naija resilience + dark humor.&lt;/p&gt;

&lt;p&gt;Mixed bag of shock, memes, “we move,” and sharp takes on economics. No mass mourning but more “the market is still here, just new apps on the ranking board.”&lt;/p&gt;

&lt;p&gt;Ninja Lesson from the Dojo&lt;br&gt;
Uber didn’t “fail” Nigeria so much as the brutal economics of African ride-hailing (high costs, low margins, fierce competition) forced a strategic pivot. They’re still in the game, just via delivery now lol. For local platforms and drivers, this is open season to level up reliability, pricing, and driver pay. For riders? Download the alternatives and keep moving. Traffic waits for no one, not even Silicon Valley giants.&lt;/p&gt;

&lt;p&gt;Stay sharp, Code Ninjas. The streets are always rewriting the code. Next mission drop soon. Shadow on. 🥷&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Extracting a React presence hook from a production event app</title>
      <dc:creator>devhabeeb</dc:creator>
      <pubDate>Wed, 12 Aug 2026 00:40:06 +0000</pubDate>
      <link>https://dev.to/devhabeeblateef/extracting-a-react-presence-hook-from-a-production-event-app-3gdg</link>
      <guid>https://dev.to/devhabeeblateef/extracting-a-react-presence-hook-from-a-production-event-app-3gdg</guid>
      <description>&lt;p&gt;&lt;em&gt;How we turned a battle-tested Supabase Realtime Presence layer into react-supabase-presence&lt;/em&gt;&lt;br&gt;
Real-time “who is in the room” sounds simple until you ship it on phones.&lt;/p&gt;

&lt;p&gt;Tabs freeze. Networks drop. React Strict Mode double-mounts effects. Supabase will often restore the socket for you — but presence track state does not magically re-announce itself. If you do not re-track after resubscribe, other clients still think you are offline.&lt;/p&gt;

&lt;p&gt;We hit that in production while building an event networking product (QR check-in, live roster, ephemeral rooms). The presence logic had to be honest in the UI: not a single boolean “connected,” but a small state machine the interface could show without lying.&lt;/p&gt;

&lt;p&gt;That code is now open source:&lt;br&gt;
npm: react-supabase-presence&lt;br&gt;
GitHub: devhabeeblateef/react-supabase-presence&lt;br&gt;
License: MIT&lt;/p&gt;

&lt;p&gt;The problem we actually had&lt;br&gt;
Supabase Realtime Presence is a good primitive. The gaps show up at the edges:&lt;/p&gt;

&lt;p&gt;Lifecycle — subscribe → track → sync/join/leave. Miss a re-track after reconnect and your user vanishes for everyone else.&lt;br&gt;
Mobile browsers — background tabs can freeze sockets without a clean CLOSED event. Coming back to the tab should re-announce.&lt;br&gt;
UI honesty — “loading” vs “live” vs “trying again” are different states. Collapsing them into one spinner trains users to ignore the product.&lt;/p&gt;

&lt;p&gt;App boundaries — roster, roles, and business logic should not live inside the presence hook. The hook should only answer: who is online, and is the channel healthy?&lt;/p&gt;

&lt;p&gt;We implemented that as a React hook inside the product first, then extracted it so the package has zero knowledge of events, QR codes, or billing.&lt;/p&gt;

&lt;p&gt;What the hook does&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="s2"&gt;`import { useEventPresence } from "react-supabase-presence";
import type { EventPresence, PresenceStatus } from "react-supabase-presence";
TypeScriptconst { online, status, version } = useEventPresence(
  supabase,   // your browser Supabase client
  channelKey, // stable room / event id
  selfId      // stable presence key for the current user
);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behaviour that mattered in production&lt;/p&gt;

&lt;p&gt;Channel name is derived as presence:${channelKey} with config.presence.key = selfId.&lt;br&gt;
On SUBSCRIBED, the hook tracks { user_id, at }.&lt;br&gt;
On CHANNEL_ERROR / TIMED_OUT / CLOSED, status becomes reconnecting (the client library may still recover underneath).&lt;br&gt;
On visibilitychange → visible, it re-tracks so a returning mobile tab reappears.&lt;/p&gt;

&lt;p&gt;Cleanup removes the channel; no shared global channel name that breaks under Strict Mode remounts.&lt;/p&gt;

&lt;p&gt;You own the SupabaseClient. The library does not create clients, read env vars, or assume your schema.&lt;/p&gt;

&lt;p&gt;Minimal example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="s2"&gt;`"use client";
import { createClient } from "@supabase/supabase-js";
import { useEventPresence } from "react-supabase-presence";

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);

export function Room({ roomId, userId }: { roomId: string; userId: string }) {
  const { online, status, version } = useEventPresence(
    supabase,
    roomId,
    userId
  );

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Status: {status}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;
        {online.size} online (v{version})
      &amp;lt;/p&amp;gt;
      &amp;lt;ul&amp;gt;
        {[...online].map((id) =&amp;gt; (
          &amp;lt;li key={id}&amp;gt;{id}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install: npm install react-supabase-presence&lt;br&gt;
Peer dependencies: react (≥18) and @supabase/supabase-js (^2.40).&lt;/p&gt;

&lt;p&gt;Design choices (and non-goals)&lt;br&gt;
In scope for v0.1&lt;/p&gt;

&lt;p&gt;Presence subscribe + track + state aggregation&lt;br&gt;
Explicit connection state for UI&lt;br&gt;
Tab-visible re-track&lt;br&gt;
TypeScript types exported from the package root&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Out of scope (on purpose)&lt;/strong&gt;&lt;br&gt;
Authentication&lt;br&gt;
Authorization / RLS policy design&lt;br&gt;
Handshakes, chat, or matching&lt;br&gt;
Rendering components (dots, avatars, lists)&lt;/p&gt;

&lt;p&gt;Those belong in the product. Keeping them out is what makes the package reusable and reviewable.&lt;br&gt;
The product that motivated this work still uses the published package for its live room roster — same API, one implementation path.&lt;/p&gt;

&lt;p&gt;Why open source this slice&lt;br&gt;
Presence is a sharp edge many Supabase + React apps re-implement poorly. Publishing a small, MIT-licensed hook:&lt;/p&gt;

&lt;p&gt;Documents the reconnect and visibility behaviour in public&lt;br&gt;
Gives others a starting point that is not tied to one startup’s domain model&lt;br&gt;
Forces a clean boundary: if it needs your event table, it does not belong in the library&lt;/p&gt;

&lt;p&gt;If you find bugs or want a multi-tab leader election helper, issues and PRs are welcome on the repo.&lt;/p&gt;

&lt;p&gt;Links&lt;br&gt;
npm: &lt;a href="https://www.npmjs.com/package/react-supabase-presence" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/react-supabase-presence&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://github.com/devhabeeblateef/react-supabase-presence" rel="noopener noreferrer"&gt;https://github.com/devhabeeblateef/react-supabase-presence&lt;/a&gt;&lt;br&gt;
License: MIT&lt;/p&gt;

</description>
      <category>react</category>
      <category>supabase</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>I’m new here</title>
      <dc:creator>devhabeeb</dc:creator>
      <pubDate>Tue, 25 Oct 2022 19:02:55 +0000</pubDate>
      <link>https://dev.to/devhabeeblateef/im-new-here-5c7c</link>
      <guid>https://dev.to/devhabeeblateef/im-new-here-5c7c</guid>
      <description>&lt;p&gt;Hello World! 🤓 &lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
