Skip to content

The Broker app

The Broker app (apps/orascom-broker-app) is the portal for external brokers who sell ODH units on commission. Its defining quirk: one build serves two personas — a role=BROKER group and a role=SALES_MANAGER group — and which one you get is decided at login.

  • Entry: src/main.tsx wraps <App> in HelmetProviderI18nextProviderQueryClientProvider (React Query) → ProSidebarProvider (+ Sentry). src/app/app.tsx provides USER_CONTEXTCompareUnitsCurrency (app.tsx:41).
  • Router: basename = process.env.NX_BROKER_PATH ?? '/' (routes.tsx:338).
  • 38 routes / screens: 8 auth/onboarding + 27 broker + 3 sales-manager.
  • API: one ENDPOINTS map with two prefixes — broker (call it {b}) and sales-manager ({sm}) — over base host NX__BROKER_API_ENDPOINT; a few auth paths are prefix-less absolute.

Login is email + password for both roles (pages/login, Authentication.loginPOST {baseHost}/login). On success the token is written to localStorage[NX_BROKER_ACCESS_TOKEN_KEY]; BROKER lands on /, SALES_MANAGER on /commissions-analytics. OTP is used only for Oman onboarding, never for standard login. There is no refresh tokenuserDataLoader drops the token and redirects to /login on failure.

The broker home: recent updates, new launches, and shortcuts into units and EOIs. pages/dashboard.

Broker app dashboard — recent updates, launches, and unit/EOI shortcuts (names blurred).

The deal pipeline — lead → meeting → invoice

Section titled “The deal pipeline — lead → meeting → invoice”

A broker’s core job is registering leads and driving them to a sale that earns commission.

  1. Register a deal. /new-deal (or /unit-details/:unitId/new-deal to pre-link a unit) creates a lead via createLead (POST {b}/leads). A lead-creation-limit-modal enforces the per-broker, per-destination cap (leadCreationLimit{b}/leads/count).

    Broker “New Deal” form — registering a lead, pre-linkable to a unit.

  2. Work the deal. /my-deals lists the broker’s deals; /deal-details/:dealId/:countryId/… (pages/deal-details) shows the lifecycle, scheduled meetings (/new-meetingcreateMeeting), and the sales invoice.

    Broker “My Deals” — the broker’s registered deals/leads (cropped to avoid client PII).

  3. Submit the commission invoice. From a deal, submitInvoice (POST .../{dealId}/sales_invoices) files the sales invoice that drives the broker’s commission.

Brokers also submit paid Expressions of Interest against launches on a client’s behalf. The full agent-side flow — the async CRM job and the 24-hour tokenized payment link — is documented in Submitting an EOI. In the app it spans three screens:

Create (/eoi/create/:launchSlug, pages/create-eoi):

Broker “Create EOI” form — the agent fills the client’s details and unit preferences.

List (/expression-of-interest, pages/eoi-listing) — filtered by payment status:

Broker “EOI Submissions” list — All / Pending Confirmation / Confirmed Payment / Requires Action tabs.

Detail (/expression-of-interest-details/:launchId/:eoiId, pages/eoi-details) — client info, personal ID, the tokenized payment link (resend/copy), and the units of interest:

Broker “EOI Submission Details” — client info, payment link, and units of interest (client name, phone, email, national ID, and the payment token all blurred).

Brokers browse the sellable inventory and generate sales offers for clients (api/unit.ts).

  • Primary Units (/primary-units) — the listing/search grid.

    Broker “Primary Units” — the units listing grid with filters.

  • Launch details (/launch-details/:launchId) — the launch a broker sells into.

    Broker “Launch details” — bank/facilities and the EOI entry point for a launch.

  • Unit details (/unit-details/:unitId) — payment terms, an async sales-offer PDF (generateSalesOfferAsync → poll checkSalesOfferStatus), and a share-reservation link. Plus Saved Units (/saved-units), Resale Units (/resale-units), and Compare (/compare-properties, with CSV export).

/analytics (pages/broker-analytics) is the broker’s own performance view: lead lifecycle counts, sales per destination/unit-type, commissions, revenue insights, and an agents/commissions/company ranking.

Broker Analytics — revenue and commissions insights plus a brokers-ranking leaderboard (broker names blurred).

The same build, entered by a SALES_MANAGER user, exposes three manager dashboards under the {sm} prefix (pages/sales-manager-*, api/analytics-sales-manager.ts):

  • /commissions-analytics — the SM landing: broker commissions breakdown + details.
  • /revenue-analytics — revenue insights, sales per destination, international sales.
  • /rankings — broker / brokerage / sales-manager rankings.

Oman has a distinct, multi-step pre-registration an ordinary broker signup doesn’t: /sign-up-oman/:brokerType (ambassador vs firm), email-OTP verification, company details, and document + contract upload, tracked at /application-status (api/oman-registration.ts, {b}/oman-pre-registration-applications/…). After approval, ongoing documents are managed at /my-registration-documents (api/oman-application.ts). The reviewer side lives in the CMS — see Oman broker pre-registration.

/notifications (pages/updates) — the recent-updates feed (getRecentUpdatesGET {b}/user/notifications).

Broker notifications — the recent-updates feed (client names blurred).

  • Dual-role build. BROKER vs SALES_MANAGER are separate route groups with different API prefixes; getHomePathForRole decides the landing page. Don’t put a broker behavior on a sales-manager route.
  • Two API prefixes in one map. {b} (NX__BROKER_ENDPOINT_PREFIX) and {sm} (NX__SALES_MANAGER_ENDPOINT_PREFIX), plus a few prefix-less absolute auth paths.
  • Email+password login; OTP is onboarding-only. No refresh token.
  • Whitelabel branding. Brokers can upload a logo (uploadWhitelabelLogo + change-logo-modal) for a branded portal.
  • Walkthrough routes are flag-gated (/unit-details/walkthrough, /deal-details/walkthrough/…) behind WALKTHROUGH_LOCALSTORAGE_KEY.