Loading…
Loading…
OOGO is a production-focused software project built by Sadam Hussain using React, Redux, Bootstrap, and related technologies.
Bilingual UAE marketplace with structural RTL architecture: layout, navigation, and typography invert for Arabic, not just text. Three portals share one Redux entity layer. Outcome: localization as architecture, not translation.
Tech Stack


Status
Production Ready
Type
Enterprise platform
Led frontend engineering for an enterprise multi-vendor marketplace platform serving a large and growing user base across the UAE market, architecting the frontend for three distinct portals (Customer, Vendor, Admin) with shared business logic and role-specific interfaces.
Architected a modular React application with Redux for centralized state management, designing a store architecture that shares entity state (products, orders, inventory) across portals while keeping portal-specific UI state isolated.
Implemented structural RTL (Right-to-Left) support as a core architectural concern - not just CSS `direction: rtl` but full layout inversion including component alignment, icon mirroring, navigation flow reversal, and culturally appropriate interaction patterns for Arabic users.
Built a comprehensive i18n system supporting seamless runtime language switching between Arabic and English, handling bidirectional text rendering, locale-specific number and currency formatting, and font stack management for Arabic typography.
Integrated localized payment gateways including Stripe for international transactions and regional UAE processors for local payment methods, implementing payment method selection logic based on user locale and transaction currency.
Optimized product discovery and search performance through memoized Redux selectors, denormalized state shapes for high-frequency reads, and intelligent caching strategies that reduced unnecessary re-renders in listing views.
Developed location-aware vendor discovery using Google Maps API with custom Arabic/English map labels, vendor proximity search, and delivery radius visualization for local commerce logistics.
Built a mobile-first responsive experience using Bootstrap with RTL-aware grid overrides, focusing on touch-optimized product browsing, swipeable galleries, and conversion-oriented checkout flows for mobile shoppers.
Implemented vendor onboarding and management interfaces including product catalog management, order fulfillment workflows, inventory tracking, and sales analytics dashboards within the seller portal.
Established testing practices with Jest for unit testing Redux reducers, selectors, and business logic, ensuring that RTL layout behavior and language switching logic are verified programmatically.
OOGO is a multi-vendor marketplace built for the UAE, where localization is architecture, not translation. The entire spatial model inverts for Arabic: layouts, navigation, carousels, icons, typography. Three portals (customer, vendor, admin) share one Redux entity layer, and checkout routes between Stripe and regional gateways based on locale and currency.
The product unifies customer, seller, and admin experiences into one connected ecosystem backed by a shared Redux state layer. Three distinct portals share entity logic (products, orders, vendors, inventory) while maintaining role-specific interfaces and workflows. This multi-portal architecture required careful state management to ensure that an order status update in the admin portal is immediately reflected in both the customer and vendor views.
The UAE market demanded more than a standard marketplace solution with translated strings. The region has unique commerce characteristics: a predominantly mobile-first shopping culture, a bilingual population that switches between Arabic and English fluidly (often within the same session), regional payment methods that complement international processors, and logistics patterns built around proximity-based delivery rather than national shipping networks.
The core problem: Most e-commerce platforms treat localization as a translation layer - swap the text, add direction: rtl, and ship. This approach fails in markets like the UAE where Arabic users expect the entire spatial layout to mirror: navigation flows right-to-left, carousels swipe in the opposite direction, progress indicators reverse, and icon metaphors change (e.g., a "back" arrow points right, not left). Building this correctly requires localization to be an architectural concern, not an afterthought.
Stakeholder perspective:
Constraints that shaped the architecture:
dir attribute changes, CSS custom properties for direction-dependent values recalculate, and React re-renders all direction-sensitive components.The RTL implementation goes deeper than most localization approaches. Rather than using a single direction: rtl CSS property and hoping everything inverts correctly, the system uses a layered approach:
CSS Logical Properties: Where possible, layout uses CSS logical properties (margin-inline-start instead of margin-left) so that values automatically flip with the document direction. This handles the majority of spacing and alignment without conditional logic.
Direction-Aware Components: Components that have inherent directionality (carousels, progress bars, breadcrumbs, pagination) receive a direction prop from the i18n context and render their internal layout accordingly. A carousel swipes left-to-right in LTR mode and right-to-left in RTL mode.
Icon Mirroring: Directional icons (arrows, chevrons, navigation indicators) are mirrored in RTL mode using CSS transforms. Non-directional icons (search, settings, user) remain unchanged. The icon system maintains a registry of which icons are directional to handle this automatically.
Bootstrap Grid Overrides: Bootstrap's grid system required custom overrides for RTL column ordering. A utility layer swaps col-*-push and col-*-pull classes in RTL mode and reverses flex direction on row components.
This structured approach means that new components automatically handle RTL correctly when they use the provided layout primitives, rather than requiring manual RTL testing and adjustment for every new feature.
The state architecture separates concerns across three layers:
This layered approach prevents the common multi-portal pitfall where shared state becomes entangled with portal-specific UI concerns, making the codebase hard to maintain as portals evolve independently.
The payment architecture uses a strategy pattern where each payment gateway implements a common interface (initialize, tokenize, confirm, handleWebhook). A routing layer selects the appropriate strategy based on:
The checkout UI dynamically renders payment method options based on the routing layer's determination, so users only see payment methods that are available for their specific transaction context.
The most architecturally challenging aspect of OOGO was building a truly bidirectional interface that doesn't just translate text but inverts the entire spatial model of the application.
The Problem: Most RTL implementations are superficial - they add dir="rtl" to the HTML document and let CSS direction handle the rest. This works for basic text alignment but fails for complex UI patterns: flex layouts with mixed-direction children, absolutely positioned elements (tooltips, dropdowns, popovers), Canvas/SVG-based visualizations, and third-party components (Google Maps, Stripe Elements) that have their own layout assumptions.
The Challenges Solved:
Mixed-Direction Content: Product listings contain both Arabic and English text (a product might have an Arabic title but an English brand name). The rendering engine uses Unicode bidirectional algorithm (Bidi) attributes to handle inline mixed-direction text correctly, wrapping segments with appropriate dir attributes so the browser's text rendering engine handles character ordering.
Third-Party Component Integration: Google Maps and Stripe Elements have their own layout engines that don't automatically respond to document-level dir changes. The map component manually repositions controls (zoom buttons, fullscreen toggle) for RTL mode and renders Arabic map labels through the Maps API's language configuration. Stripe Elements are configured with locale-appropriate formatting but render in an iframe with its own document context.
Animation Direction: CSS transitions and JavaScript animations that use horizontal movement (slide-in menus, carousel transitions, progress bar fills) need to reverse their direction in RTL mode. The animation system reads the current locale direction and applies transform adjustments so that a "slide-in from left" animation becomes "slide-in from right" in RTL.
Form Layout: Form fields in RTL mode need label-to-input alignment reversal, placeholder text direction changes, and validation message positioning swaps. The form component system handles this through direction-aware wrapper components rather than requiring each form to implement its own RTL adjustments.
Data Table Direction: Tables with both Arabic and English column headers need intelligent alignment - text columns align based on content language, while numeric columns maintain consistent right-alignment regardless of document direction. The table component inspects content type to apply appropriate alignment rules.
Why this approach: The investment in structural RTL support (rather than quick CSS fixes) paid off as the application grew. New features built using the provided layout primitives automatically render correctly in both directions without dedicated RTL testing or bug-fixing cycles. The alternative - fixing RTL bugs reactively as they're reported - creates an ever-growing maintenance burden and degrades the Arabic user experience.
Challenge: CSS direction: rtl doesn't handle all layout patterns - flex containers with explicit margin-left/padding-right, absolutely positioned elements, and CSS Grid column placement all break in RTL mode.
Approach: Adopted CSS logical properties (margin-inline-start, padding-inline-end) throughout the codebase and built direction-aware wrapper components for patterns that logical properties don't cover (absolute positioning, canvas rendering). Created a linting rule that flags physical direction properties (margin-left, padding-right) in code review.
Why: Logical properties let the browser handle direction switching automatically for the majority of layout cases. The linting rule prevents regression by catching new code that uses physical properties instead of logical ones.
Challenge: Three portals sharing entity state (Products, Orders) created a risk of state mutations in one portal causing unexpected behavior in another. Approach: Enforced immutable state updates through Redux Toolkit's Immer integration and strict action typing. Each portal dispatches domain-specific actions that are handled by shared reducers with well-defined state transitions. Added integration tests that verify cross-portal state consistency after multi-step workflows. Why: Without immutability guarantees, shared state in a multi-portal architecture becomes a debugging nightmare. Redux Toolkit's Immer integration makes immutable updates ergonomic while TypeScript ensures action payloads are correct at compile time.
Challenge: Arabic typography required different line heights, letter spacing, and font sizes than the English layout, causing text overflow and alignment issues when switching languages. Approach: Created locale-aware design tokens that adjust typography values based on the active language. Arabic font stacks use dedicated fonts optimized for connected Arabic script (Noto Sans Arabic, Tajawal) with adjusted line-height multipliers. Theme values switch dynamically when the locale changes. Why: Latin and Arabic scripts have fundamentally different vertical metrics - Arabic script has more pronounced ascenders and descenders, and connected letter forms create different visual density. A single set of typography values produces poor results in one language or the other.
Challenge: Integrating regional UAE payment processors alongside Stripe required handling different authentication flows, tokenization approaches, and error response formats. Approach: Built a payment gateway abstraction layer using the strategy pattern, where each gateway implements a common interface. The checkout flow interacts with the abstraction layer, unaware of which gateway is processing the transaction. Gateway selection happens automatically based on locale and payment method type. Why: Direct integration of multiple payment gateways without an abstraction layer would scatter gateway-specific logic throughout the checkout code. The strategy pattern isolates gateway-specific complexity while presenting a unified interface to the rest of the application.
OOGO demonstrated that localization is an architectural challenge, not a content challenge. Building for the UAE market required thinking about "the direction of the user journey" from day one - not just which language the text is in, but which direction the eye scans, which side navigation anchors to, and which way gestures flow.
Patterns I'd reuse:
What I'd reconsider:
rtl: variant) would reduce the custom override surface significantly.Trade-offs acknowledged:
/ar/ and /en/ URL prefixes), accepting slightly heavier client bundles in exchange for instant language switching without navigation.