From 429eab90dd0fa0451a3176958c29a094e7282d2b Mon Sep 17 00:00:00 2001 From: AliameenXBT Date: Fri, 3 Apr 2026 19:24:10 +0100 Subject: [PATCH 001/579] chore: rebrand platform from Swifta to twizrr project-wide --- DESIGN.md | 533 +++++++++++++++--- README.md | 20 +- apps/backend/Dockerfile | 4 +- apps/backend/README.md | 4 +- apps/backend/package.json | 6 +- .../src/common/decorators/roles.decorator.ts | 2 +- .../common/filters/global-exception.filter.ts | 2 +- .../common/guards/merchant-verified.guard.ts | 2 +- apps/backend/src/common/guards/roles.guard.ts | 2 +- .../response-transform.interceptor.ts | 2 +- .../middleware/merchant-context.middleware.ts | 2 +- apps/backend/src/common/types/express.d.ts | 2 +- apps/backend/src/common/utils/pagination.ts | 2 +- .../src/modules/admin/admin-cron.service.ts | 2 +- .../src/modules/admin/admin.controller.ts | 2 +- .../src/modules/admin/admin.service.ts | 2 +- .../src/modules/admin/audit-log.controller.ts | 2 +- .../src/modules/auth/auth.controller.ts | 12 +- apps/backend/src/modules/auth/auth.service.ts | 4 +- .../src/modules/auth/dto/register.dto.ts | 2 +- .../modules/auth/internal-auth.controller.ts | 4 +- .../auth/strategies/jwt-access.strategy.ts | 6 +- .../auth/strategies/jwt-refresh.strategy.ts | 4 +- .../src/modules/buyer/buyer.controller.ts | 2 +- .../src/modules/cart/cart.controller.ts | 2 +- apps/backend/src/modules/cart/cart.service.ts | 2 +- .../src/modules/cart/dto/add-to-cart.dto.ts | 2 +- .../modules/category/category.controller.ts | 2 +- .../backend/src/modules/dva/dva.controller.ts | 2 +- .../src/modules/email/email.service.ts | 18 +- .../modules/inventory/inventory.controller.ts | 2 +- .../modules/inventory/inventory.service.ts | 2 +- .../modules/logistics/logistics.controller.ts | 2 +- .../modules/merchant/merchant.controller.ts | 2 +- .../src/modules/merchant/merchant.service.ts | 2 +- .../notification-trigger.service.ts | 4 +- .../notification/notification.controller.ts | 2 +- .../notification/notification.processor.ts | 2 +- .../modules/order/dto/checkout-cart.dto.ts | 2 +- .../modules/order/dto/create-tracking.dto.ts | 2 +- .../src/modules/order/invoice.service.ts | 4 +- .../src/modules/order/order-state-machine.ts | 2 +- .../src/modules/order/order.controller.ts | 2 +- .../src/modules/order/order.service.ts | 2 +- .../src/modules/payment/payment.controller.ts | 2 +- .../src/modules/payment/payment.service.ts | 2 +- .../src/modules/payout/payout.service.ts | 2 +- .../src/modules/product/product.controller.ts | 2 +- .../src/modules/product/product.service.ts | 2 +- .../src/modules/reorder/reorder.controller.ts | 2 +- .../src/modules/review/review.controller.ts | 2 +- .../src/modules/review/review.service.ts | 2 +- .../modules/supplier/supplier.controller.ts | 2 +- .../src/modules/supplier/supplier.service.ts | 2 +- .../trade-financing/bnpl-partner.interface.ts | 4 +- .../trade-financing-partner.interface.ts | 2 +- .../trade-financing.controller.ts | 2 +- .../src/modules/upload/upload.controller.ts | 4 +- .../src/modules/upload/upload.service.ts | 2 +- apps/backend/src/modules/ussd/ussd.service.ts | 16 +- .../verification/verification.controller.ts | 2 +- .../modules/verification/verification.dto.ts | 2 +- .../verification/verification.service.ts | 2 +- .../whatsapp/whatsapp-buyer-auth.service.ts | 4 +- .../whatsapp/whatsapp-buyer.constants.ts | 8 +- .../whatsapp/whatsapp-buyer.service.ts | 18 +- .../whatsapp/whatsapp-onboarding.service.ts | 22 +- .../whatsapp/whatsapp-supplier.service.ts | 2 +- .../modules/whatsapp/whatsapp.constants.ts | 4 +- .../src/modules/whatsapp/whatsapp.module.ts | 2 +- .../src/modules/whatsapp/whatsapp.service.ts | 16 +- apps/backend/src/prisma/seed.ts | 8 +- .../src/queue/auto-confirm.processor.ts | 8 +- .../src/queue/checkout-reminder.processor.ts | 6 +- apps/backend/test/helpers/test-setup.ts | 6 +- apps/backend/test/jest-e2e.json | 2 +- apps/web/README.md | 10 +- apps/web/next.config.mjs | 6 +- apps/web/package.json | 4 +- apps/web/public/manifest.json | 4 +- apps/web/src/app/(auth)/admin/join/page.tsx | 4 +- apps/web/src/app/(auth)/admin/login/page.tsx | 8 +- .../app/(auth)/admin/verify-token/page.tsx | 4 +- apps/web/src/app/(auth)/login/page.tsx | 4 +- apps/web/src/app/(auth)/register/page.tsx | 6 +- .../app/(dashboard)/admin/analytics/page.tsx | 2 +- .../app/(dashboard)/admin/categories/page.tsx | 2 +- .../app/(dashboard)/admin/settings/page.tsx | 2 +- .../app/(dashboard)/buyer/catalogue/page.tsx | 2 +- .../buyer/checkout/[productId]/page.tsx | 4 +- .../app/(dashboard)/buyer/merchants/page.tsx | 2 +- .../(dashboard)/buyer/notifications/page.tsx | 2 +- .../(dashboard)/buyer/orders/[id]/page.tsx | 8 +- .../buyer/orders/[id]/receipt/page.tsx | 8 +- .../buyer/orders/[id]/review/page.tsx | 2 +- .../buyer/orders/payment/callback/page.tsx | 4 +- .../app/(dashboard)/buyer/profile/page.tsx | 2 +- .../src/app/(dashboard)/buyer/saved/page.tsx | 2 +- .../web/src/app/(dashboard)/m/[slug]/page.tsx | 2 +- .../(dashboard)/merchant/dashboard/page.tsx | 2 +- .../merchant/notifications/page.tsx | 2 +- .../orders/[id]/dispatch-slip/page.tsx | 6 +- .../(dashboard)/merchant/orders/[id]/page.tsx | 6 +- .../app/(dashboard)/merchant/orders/page.tsx | 4 +- .../app/(dashboard)/merchant/payouts/page.tsx | 4 +- .../merchant/products/[id]/edit/page.tsx | 2 +- .../(dashboard)/merchant/products/page.tsx | 2 +- .../(dashboard)/merchant/settings/page.tsx | 6 +- .../merchant/trade-financing/page.tsx | 2 +- .../merchant/verification/page.tsx | 4 +- .../app/(dashboard)/merchant/wallet/page.tsx | 2 +- .../(dashboard)/merchant/wholesale/page.tsx | 4 +- apps/web/src/app/layout.tsx | 8 +- apps/web/src/app/page.tsx | 8 +- .../register-flow/account-details-step.tsx | 2 +- .../registration-success-step.tsx | 4 +- .../register-flow/role-selection-step.tsx | 4 +- .../src/components/buyer/cart/cart-view.tsx | 4 +- .../buyer/catalogue/catalogue-grid.tsx | 2 +- .../buyer/catalogue/category-card.tsx | 2 +- .../buyer/catalogue/category-stories-bar.tsx | 2 +- .../catalogue/merchant-spotlight-carousel.tsx | 2 +- .../buyer/checkout/instant-checkout-modal.tsx | 8 +- .../buyer/dashboard/active-deliveries.tsx | 2 +- .../buyer/dashboard/buyer-summary-cards.tsx | 2 +- .../buyer/dashboard/delivery-card.tsx | 2 +- .../buyer/merchants/merchant-discovery.tsx | 4 +- .../buyer/orders/buyer-order-actions.tsx | 6 +- .../buyer/orders/buyer-order-summary.tsx | 4 +- .../buyer/orders/order-info-sidebar.tsx | 2 +- .../components/buyer/orders/orders-view.tsx | 2 +- .../src/components/layout/admin-header.tsx | 2 +- .../src/components/layout/buyer-sidebar.tsx | 2 +- .../src/components/layout/merchant-header.tsx | 4 +- .../components/layout/merchant-sidebar.tsx | 2 +- .../src/components/layout/mode-switcher.tsx | 4 +- .../merchant/dashboard/kanban-order-card.tsx | 2 +- .../merchant/orders/dispatch-modal.tsx | 4 +- .../merchant/orders/fulfillment-details.tsx | 2 +- .../merchant/orders/merchant-order-guide.tsx | 2 +- .../merchant/orders/merchant-orders-table.tsx | 2 +- .../merchant/orders/order-drawer.tsx | 4 +- .../orders/order-reference-sidebar.tsx | 4 +- .../merchant/products/inventory-row.tsx | 2 +- .../products/merchant-inventory-table.tsx | 2 +- .../products/merchant-products-grid.tsx | 2 +- .../products/product-creation-drawer.tsx | 4 +- .../merchant/products/product-modal.tsx | 2 +- .../merchant/profile/edit-profile-modal.tsx | 4 +- .../profile/merchant-profile-view.tsx | 4 +- .../merchant/verification-banner.tsx | 4 +- .../wallet/merchant-wallet-dashboard.tsx | 2 +- .../merchant/wholesale/wholesale-card.tsx | 2 +- .../src/components/shared/product-card.tsx | 2 +- .../components/shared/product-detail-view.tsx | 10 +- .../components/shared/verification-badge.tsx | 2 +- apps/web/src/components/ui/money.tsx | 2 +- .../src/components/ui/verification-badge.tsx | 2 +- apps/web/src/hooks/use-buyer-orders.ts | 2 +- apps/web/src/hooks/use-merchant-data.ts | 2 +- apps/web/src/hooks/use-merchant-orders.ts | 2 +- apps/web/src/hooks/use-notifications.ts | 2 +- apps/web/src/hooks/use-order.ts | 2 +- apps/web/src/lib/api-client.ts | 4 +- apps/web/src/lib/api/auth.api.ts | 4 +- apps/web/src/lib/api/cart.api.ts | 2 +- apps/web/src/lib/api/category.api.ts | 2 +- apps/web/src/lib/api/inventory.api.ts | 2 +- apps/web/src/lib/api/location.api.ts | 2 +- apps/web/src/lib/api/merchant.api.ts | 2 +- apps/web/src/lib/api/notification.api.ts | 2 +- apps/web/src/lib/api/order.api.ts | 2 +- apps/web/src/lib/api/payment.api.ts | 2 +- apps/web/src/lib/api/product.api.ts | 2 +- apps/web/src/lib/api/review.api.ts | 2 +- apps/web/src/lib/api/supplier.api.ts | 2 +- apps/web/src/lib/validations/auth.ts | 2 +- apps/web/src/providers/auth-provider.tsx | 4 +- apps/web/tsconfig.json | 2 +- docker-compose.yml | 2 +- lint_output.txt | Bin 452 -> 0 bytes package.json | 2 +- packages/shared/README.md | 10 +- packages/shared/package.json | 2 +- packages/shared/src/constants/defaults.ts | 2 +- pnpm-lock.yaml | 8 +- precommit.ps1 | 2 +- render.yaml | 4 +- replace_swifta.js | 77 +++ 189 files changed, 885 insertions(+), 409 deletions(-) delete mode 100644 lint_output.txt create mode 100644 replace_swifta.js diff --git a/DESIGN.md b/DESIGN.md index 431f9952..a9531f61 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,67 +1,466 @@ -This Swifta V1 Design System Specification serves as the technical blueprint for implementing the high-contrast, utilitarian B2B platform across mobile and desktop. - -1. Core Philosophy & Aesthetic Rules -Mission: A "No-Nonsense" industrial tool for high-value commerce. The UI must feel as stable and heavy as the materials (cement, iron) being sold. -Theme: Strict Light Mode. High-contrast (minimum 4.5:1 ratio). -Visual Language: -Borders: Solid 1px or 1.5px borders (#D1D5DB or #E5E7EB). No "soft" borders. -Corners: Sharp (4px radius max) to convey precision and industrial strength. -Shadows: Submerged or flat shadows only. Use box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1). No large, blurry elevations. -Effects: Zero Glassmorphism, Zero Bubbly/Rounded UI, Zero gradients. - -2. Color Palette -Backgrounds: Primary: #FFFFFF (White), Secondary: #F9FAFB (Light Gray). -Brand Primary: #1E3A8A (Deep Industrial Blue) or #C2410C (Industrial Orange) for Call-to-Actions (CTAs). -Status Colors: -Success/Paid: #15803D (Forest Green). -Alert/Low Stock: #B91C1C (Strong Red). -In-Transit: #0369A1 (Steel Blue). -Typography: Primary: #111827 (Almost Black), Secondary: #4B5563 (Slate Gray). - -3. Layout & Navigation Patterns -Mobile Navigation: 5-item bottom bar (Catalogue, Quotes, Orders, Messages, Profile). -Desktop Navigation: 240px fixed left-side vertical navigation rail. Persistent and solid. -Command Center (State Machine): All order-related screens follow a strict 4-stage pipeline: -Pending Quotes: Negotiation phase. -Awaiting Dispatch: Escrow funded, stock preparation. -In Transit: Material moving, driver on-site. -Payout Completed: Transaction closed. - -4. Component Specifications -The Quote Card (RFQ Thread): -A structured container with explicit fields: Unit Price, Delivery Fee, Total, and Expiry Date. -Must use tabular alignment for numbers to look like an official invoice. -The OTP Pad (Escrow Release): -High-contrast 6-digit input. Each digit in a separate box with a 2px border. -Large, touch-friendly targets for use in outdoor, dusty construction environments. -The Data Table (Inventory/Management): -Dense, high-information rows. -Sticky headers. High-contrast row-hover state (#F3F4F6). -No "hidden" actions. Every row should have visible 'Edit' or 'Update' buttons. - -5. Critical Product Rules -No Price Visibility: Prices are never shown in the Public Catalogue. They only appear within the private Negotiation Thread or on a Quote Card. -CTA Priority: The primary action is always 'Request Quote' or 'Send RFQ'. There is no 'Cart' functionality. - -The Typography Scale & Text Hierarchy has been defined to ensure maximum legibility for merchants and contractors, even in high-glare outdoor environments: - -Typography Scale & Text Hierarchy: A technical documentation screen that specifies an industrial font system. It uses a clean, bold sans-serif for headings and a monospaced font for data-heavy fields (like SKUs and Naira amounts) to ensure tabular alignment and precision. -Swifta V1 Typography Scale -Role Desktop Size Mobile Size Weight Line Height Usage -H1 - Dashboard Title 32px 24px 700 (Bold) 1.2 Main Page Titles -H2 - Section Header 24px 20px 600 (Semi) 1.3 Kanban Columns, Card Titles -H3 - Card Subhead 18px 16px 600 (Semi) 1.4 Product Names, Escrow Balance -Body - Standard 16px 16px 400 (Reg) 1.5 Chat Threads, Product Details -Body - Small 14px 14px 400 (Reg) 1.5 Merchant Names, Metadata -Data / Monospace 14px 14px 500 (Med) 1.0 SKUs, Prices, OTP Codes -Button Text 16px 16px 600 (Semi) 1.0 Request Quote, Generate OTP -Implementation Note: Use Inter or System Sans-Serif for standard text and Roboto Mono or IBM Plex Mono for currency and SKU data to maintain that "banking/logistics" feel. - -6. Tech Stack & Implementation Standards -Next.js Architecture: -- Global layouts (MerchantHeader, MerchantSidebar) reside in `apps/web/src/components/layout/`. -- Merchant Dashboard modular components (KanbanColumn, KanbanRfqCard, KanbanOrderCard) must perfectly replicate the B2B Stitch design and reside in `apps/web/src/components/merchant/dashboard/`. -- Page views (like `page.tsx`) should act as data-fetching containers (`useMerchantDashboard`) and layout shells, passing data down to pure presentation components without injecting redundant old KPI grids unless explicitly designed. - -BigInt Serialization: -Our NestJS backend and shared types use `BigInt` for high-precision financial data (Naira/Kobo). In API boundaries and testing containers, ensure `BigInt.prototype.toJSON` is properly patched or manually converted to strings, as `JSON.stringify` natively throws errors on BigInt values. When extracting values on the frontend, always parse `totalAmountKobo` into a formatting utility (like `formatKobo` from `@swifta/shared`) rather than displaying raw integers. +# twizrr Design System v2.1 + +> **Last updated:** March 2026 +> **Replaces:** V1 B2B Industrial Design System and v2.0 amber palette (both DEPRECATED) +> **Purpose:** Technical blueprint for implementing twizrr's social commerce UI across web and mobile. Single source of truth for all design decisions. + +--- + +## 1. Core Philosophy + +**Mission:** Make buying and selling on WhatsApp feel safe, social, and effortless. + +**Design Personality:** +- **Warm, not corporate.** twizrr is a marketplace for real people, not an enterprise dashboard. The UI should feel like browsing Instagram, not filing a report. +- **Trustworthy, not flashy.** Every pixel should communicate safety — escrow protection, verified merchants, secure payments. Trust is built through clarity, not decoration. +- **Social-first.** Products are "posts." Merchants are "profiles you follow." The feed is the front door. Commerce happens inside conversations. +- **WhatsApp-native thinking.** Even on the web, design as if the buyer might switch to WhatsApp at any moment. Keep flows short, actions clear, and always offer the WhatsApp bridge. + +**Anti-patterns (never do these):** +- No enterprise dashboard aesthetics (dense tables, KPI grids, kanban boards on buyer-facing pages) +- No industrial or construction visual language +- No hidden prices — prices are always visible on product cards +- No "Request Quote" CTAs — this is direct commerce with Buy Now and Add to Cart +- No glassmorphism, no heavy gradients, no neon effects +- No dark patterns (fake urgency, hidden fees, confusing checkout) + +--- + +## 2. Color Palette + +### Brand Colors + +| Token | Hex | HSL | Usage | +|-------|-----|-----|-------| +| `brand-primary` | `#00C853` | `hsl(145, 100%, 39%)` | Primary accent — CTAs, active states, highlights, brand identity | +| `brand-primary-hover` | `#00A846` | `hsl(145, 100%, 33%)` | Hover state for primary buttons and links | +| `brand-primary-light` | `#E8F5E9` | `hsl(120, 38%, 94%)` | Subtle backgrounds for highlighted sections, success states | +| `brand-primary-dark` | `#4ADE80` | `hsl(142, 69%, 58%)` | Dark mode primary — brighter for visibility on dark backgrounds | +| `brand-secondary` | `#0F2A4A` | `hsl(213, 67%, 18%)` | Deep blue — headings, sidebar background, premium feel | +| `brand-accent` | `#D97706` | `hsl(25, 79%, 52%)` | Accent orange — ratings, stars, badges, attention items | + +### Backgrounds + +| Token | Light Mode | Dark Mode | Usage | +|-------|-----------|-----------|-------| +| `bg-primary` | `#FFFFFF` | `#0F1117` | Main page background | +| `bg-secondary` | `#F9FAFB` | `#1A1D27` | Card backgrounds, sidebar, sections | +| `bg-tertiary` | `#F3F4F6` | `#242836` | Input fields, hover states, category pills | +| `bg-elevated` | `#FFFFFF` | `#1E2230` | Elevated cards, modals, dropdowns | + +### Text + +| Token | Light Mode | Dark Mode | Usage | +|-------|-----------|-----------|-------| +| `text-primary` | `#111827` | `#F1F2F4` | Headings, product names, prices | +| `text-secondary` | `#4B5563` | `#9CA3AF` | Descriptions, metadata, timestamps | +| `text-tertiary` | `#9CA3AF` | `#6B7280` | Placeholders, hints, disabled text | +| `text-on-brand` | `#FFFFFF` | `#FFFFFF` | Text on brand-colored buttons | + +### Status Colors + +| Token | Light Mode | Dark Mode | Usage | +|-------|-----------|-----------|-------| +| `status-success` | `#059669` | `#34D399` | Paid, delivered, verified, in stock | +| `status-warning` | `#D97706` | `#FBBF24` | Pending, dispatched, low stock | +| `status-error` | `#DC2626` | `#F87171` | Failed, cancelled, out of stock, dispute | +| `status-info` | `#2563EB` | `#60A5FA` | In transit, processing, informational | + +### Verification Badge Colors + +| Tier | Color | Icon | +|------|-------|------| +| Tier 1 — Basic | `#9CA3AF` (Gray) | Single checkmark | +| Tier 2 — Identity | `#059669` (Green) | Double checkmarks | +| Tier 3 — Business | `#2563EB` (Blue) | Blue tick | + +### Borders + +| Token | Light Mode | Dark Mode | Usage | +|-------|-----------|-----------|-------| +| `border-default` | `#E5E7EB` | `#2D3348` | Card borders, dividers | +| `border-hover` | `#D1D5DB` | `#404860` | Hover state borders | +| `border-focus` | `#00C853` | `#4ADE80` | Focus rings on inputs and interactive elements | + +### Star Ratings +- Always use `brand-accent` (#D97706 orange) for filled stars +- Empty stars use `border-default` color +- Never use green for stars — green is for CTAs and verification only + +--- + +## 3. Typography + +**Primary font:** Inter +**Monospace font:** JetBrains Mono or Roboto Mono (prices, product codes, OTP inputs) + +Remove from codebase: Outfit, DM Sans, Caveat. Consolidate to Inter only (with system sans-serif fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto). + +### Scale + +| Role | Desktop | Mobile | Weight | Line Height | Usage | +|------|---------|--------|--------|-------------|-------| +| Page title | 28px | 22px | 700 | 1.2 | "Explore Products", "My Orders" | +| Section header | 20px | 18px | 600 | 1.3 | "Top Merchants This Week", card section titles | +| Product name | 16px | 15px | 600 | 1.4 | Product card titles, merchant names | +| Body | 15px | 14px | 400 | 1.5 | Descriptions, details, chat text | +| Caption | 13px | 12px | 400 | 1.4 | Timestamps, metadata, "2h ago", "per bag" | +| Price | 18px | 16px | 700 | 1.0 | Naira amounts — always use monospace font | +| Button | 15px | 14px | 600 | 1.0 | CTA labels | +| Badge | 11px | 11px | 600 | 1.0 | Status pills, verification badges | + +### Price Display Rules +- Always use monospace font for prices +- Always prefix with Naira sign: ₦ +- Always format with commas: ₦185,000 not ₦185000 +- Never show kobo to buyers unless the price has actual kobo values +- "per unit" labels use caption size in text-secondary color + +--- + +## 4. Spacing & Layout + +### Spacing Scale (4px grid) + +| Token | Value | Usage | +|-------|-------|-------| +| `space-xs` | 4px | Tight gaps (icon-to-text, badge padding) | +| `space-sm` | 8px | Inner card padding, between inline elements | +| `space-md` | 12px | Between card sections, form field gaps | +| `space-lg` | 16px | Card padding, section spacing | +| `space-xl` | 24px | Between sections, page margins | +| `space-2xl` | 32px | Major section breaks | +| `space-3xl` | 48px | Page-level top/bottom padding | + +### Border Radius + +| Token | Value | Usage | +|-------|-------|-------| +| `radius-sm` | 6px | Buttons, badges, pills | +| `radius-md` | 10px | Input fields, small cards | +| `radius-lg` | 14px | Product cards, modal corners | +| `radius-xl` | 20px | Large cards, image containers | +| `radius-full` | 9999px | Avatars, circular buttons, category pills | + +### Shadows + +| Token | Value | Usage | +|-------|-------|-------| +| `shadow-card` | `0 1px 3px rgba(0,0,0,0.08)` | Product cards, merchant cards | +| `shadow-elevated` | `0 4px 12px rgba(0,0,0,0.1)` | Modals, dropdowns, floating elements | +| `shadow-none` | `none` | Dark mode cards (use border instead) | + +**Dark mode rule:** Replace shadows with 1px solid borders using `border-default`. Shadows are invisible on dark backgrounds. + +--- + +## 5. Component Specifications + +### Product Feed Card + +``` +┌─────────────────────────────────────────┐ +│ [Avatar] Merchant Name ✓ Follow │ ← Merchant header (avatar 32px, name 14px semibold) +│ 2h ago │ ← Timestamp (caption, text-secondary) +├─────────────────────────────────────────┤ +│ │ +│ [Product Image] │ ← 1:1 aspect ratio, radius-xl, Cloudinary w_400 +│ (tap to view detail) │ +│ │ +├─────────────────────────────────────────┤ +│ Product Name ★ 4.8 │ ← Name 16px semibold, rating with orange star +│ Description preview text that │ ← Body text, max 2 lines, text-secondary +│ truncates after two lines... │ +│ │ +│ ₦185,000 🛒 🔖 [Quick Buy] │ ← Price (monospace 18px bold), actions row +│ In stock │ ← Caption, status-success color +└─────────────────────────────────────────┘ +``` + +**Card specs:** +- Width: fill container (responsive grid: 1 col mobile, 2 col tablet, 3 col desktop) +- Padding: `space-lg` (16px) +- Border: 1px solid `border-default` +- Border radius: `radius-lg` (14px) +- Background: `bg-elevated` +- Shadow: `shadow-card` in light mode, border only in dark mode +- Image: 1:1 aspect ratio, `radius-xl` corners, Cloudinary `q_auto,f_auto,w_400` +- Quick Buy button: `brand-primary` green background, white text, `radius-sm` +- Follow link: `brand-primary` green text +- Star rating: `brand-accent` orange +- Cart and bookmark icons: `text-secondary`, `text-primary` on hover +- **ProductCard must NOT show wholesale prices** — remove all wholesale/retail price logic + +### Merchant Profile Card (Top Merchants row) + +- Horizontal scroll on mobile +- Avatar: 48px circle with 2px `brand-primary` green border for verified +- Background: `bg-secondary` +- Border radius: `radius-full` on container (pill shape) +- Padding: `space-sm` vertical, `space-lg` horizontal +- Star rating: `brand-accent` orange + +### Category Pill Bar + +- Horizontal scroll, no wrapping +- Active pill: `brand-primary` green background, `text-on-brand` white text +- Inactive pill: `bg-tertiary` background, `text-secondary` text +- Icon above text (24px icon, 12px label) +- Border radius: `radius-full` +- Gap between pills: `space-sm` + +### Categories (official list only) + +1. Electronics +2. Fashion +3. Home & Kitchen +4. Health & Beauty +5. Food & Groceries +6. Phones & Gadgets +7. Sports & Fitness +8. Baby & Kids +9. Other + +**Never include:** Building, Building Materials, Hardware, Auto Parts, Vehicles, Wholesale + +### Search Bar + +- Full width minus sidebar +- Height: 44px (minimum touch target) +- Border radius: `radius-full` +- Background: `bg-tertiary` +- Camera icon on right for image search +- Focus state: `border-focus` green ring + +### Quick Buy Button +- Background: `brand-primary` green (#00C853) +- Text: `text-on-brand` white, 15px semibold +- Border radius: `radius-sm` (6px) +- Padding: 8px 16px +- Hover: `brand-primary-hover` (#00A846) +- Min height: 36px + +### OTP Input (Delivery Confirmation) + +- 6 separate input boxes +- Each box: 48px × 48px, `radius-md`, 2px border +- Font: monospace, 24px, bold +- Active box: `border-focus` green +- Auto-advance on digit entry +- Paste support for full 6-digit code + +### Verification Badge +- Inline after merchant name, never standalone +- Tier 1: gray checkmark (16px) +- Tier 2: double green checkmark (16px) +- Tier 3: blue tick (16px) +- Always icon, never text label + +--- + +## 6. Navigation + +### Buyer Sidebar (Desktop — 240px fixed left) + +| Section | Label | Icon | Route | +|---------|-------|------|-------| +| Browse | Catalogue | grid_view | /buyer/catalogue | +| Browse | Merchants | storefront | /buyer/merchants | +| Shopping | My Cart | shopping_cart | /buyer/cart | +| Shopping | Active Orders | local_shipping | /buyer/orders | +| Shopping | Saved Items | bookmark | /buyer/saved | +| Account | Notifications | notifications | /buyer/notifications | +| Account | Profile Settings | settings | /buyer/profile | +| — | Continue on WhatsApp | WhatsApp icon | Opens WhatsApp bot link | + +### Buyer Mobile Navigation (Bottom bar — 5 items) + +| Label | Icon | Route | +|-------|------|-------| +| Home | home | /buyer/catalogue | +| Search | search | /buyer/search | +| Cart | shopping_cart | /buyer/cart | +| Orders | receipt_long | /buyer/orders | +| Profile | person | /buyer/profile | + +### Merchant Sidebar (Desktop — 240px fixed left) + +| Section | Label | Icon | Route | +|---------|-------|------|-------| +| Store | Dashboard | dashboard | /merchant/dashboard | +| Store | Products | inventory | /merchant/products | +| Store | Orders | shopping_bag | /merchant/orders | +| Finance | Payouts | account_balance | /merchant/payouts | +| Finance | Analytics | bar_chart | /merchant/analytics | +| Account | Store Settings | settings | /merchant/settings | +| Account | Verification | verified | /merchant/verification | +| — | Switch to Buyer | swap_horiz | /buyer/catalogue | + +**Never include in any sidebar:** Wholesale, Supplies Cart, Procurement, RFQ, Quotes, Trade Financing, Supplier anything + +--- + +## 7. Public Page URL Structure + +| Page | URL Pattern | Example | +|------|------------|---------| +| Merchant store | `/@:slug` | twizrr.com/@fashionhub | +| Product detail | `/p/:productCode` | twizrr.com/p/NK-AF1-07 | +| Category browse | `/c/:categorySlug` | twizrr.com/c/electronics | +| Home / Feed | `/` | twizrr.com | + +Authenticated dashboard pages keep standard routes: `/buyer/*`, `/merchant/*`, `/admin/*` + +--- + +## 8. Responsive Breakpoints + +| Breakpoint | Width | Layout | +|-----------|-------|--------| +| Mobile | 0 — 639px | Single column, bottom nav, no sidebar | +| Tablet | 640 — 1023px | Two column feed, collapsible sidebar | +| Desktop | 1024px+ | Three column feed, fixed sidebar | + +### Mobile-Specific Rules +- Minimum touch target: 44px × 44px +- Input font size: minimum 16px (prevents iOS auto-zoom) +- Sidebar collapses to hamburger menu +- Bottom navigation bar: 56px height, fixed position +- Product feed: single column, full-width cards +- No hover states — use active/pressed states instead + +--- + +## 9. Image Specifications + +| Context | Dimensions | Cloudinary Transform | Aspect Ratio | +|---------|-----------|---------------------|-------------| +| Profile avatar | 200 × 200 | `w_200,h_200,c_fill,g_face,q_auto,f_auto` | 1:1 circle | +| Merchant banner | 1200 × 400 | `w_1200,h_400,c_fill,q_auto,f_auto` | 3:1 | +| Product feed thumbnail | 400 × 400 | `w_400,h_400,c_fill,q_auto,f_auto` | 1:1 | +| Product detail image | 800px wide | `w_800,q_auto,f_auto` | Original ratio | +| Category icon | 100 × 100 | `w_100,h_100,c_fill,q_auto,f_auto` | 1:1 | + +--- + +## 10. Dark Mode Rules + +- Use CSS variables / Tailwind `dark:` classes for all colors +- Never hardcode hex colors in components +- Replace shadows with borders in dark mode +- Toggle via `next-themes` with `class` strategy +- User preference persisted in localStorage + +| Element | Light | Dark | +|---------|-------|------| +| Page background | `#FFFFFF` | `#0F1117` | +| Card background | `#FFFFFF` | `#1E2230` | +| Card border | `#E5E7EB` | `#2D3348` | +| Primary text | `#111827` | `#F1F2F4` | +| Secondary text | `#4B5563` | `#9CA3AF` | +| Brand primary | `#00C853` | `#4ADE80` | +| Brand accent (stars) | `#D97706` | `#FBBF24` | +| Input background | `#F3F4F6` | `#242836` | + +--- + +## 11. Escrow Trust Indicators + +### On product cards: +- Verification badge next to merchant name +- "Escrow Protected" small shield icon near Buy button + +### On checkout: +- "Your money is protected. Payment is held securely until you confirm delivery." +- Shield icon + green accent color +- Visual flow: Pay → Held Safely → Confirm Delivery → Merchant Paid + +### On order tracking: +- "Payment held securely" (after payment, before dispatch) +- "Delivery in progress — confirm when received" (after dispatch) +- "Completed — merchant has been paid" (after confirmation) +- OTP input prominent when status is DISPATCHED + +### On merchant store page: +- Verification tier badge prominently displayed +- Star rating + total completed orders + member since date + +--- + +## 12. WhatsApp Bridge + +### Touchpoints: +- Floating WhatsApp button on bottom-right of all buyer pages +- "Continue on WhatsApp" option in checkout flow +- Product code copy with toast: "Product code copied — paste in WhatsApp to buy" +- "Share to WhatsApp" in product share options + +### WhatsApp button spec: +- Size: 56px circle +- Color: `#25D366` (official WhatsApp green) +- Icon: WhatsApp logo (white) +- Shadow: `shadow-elevated` +- Position: fixed, bottom-right, 24px from edges +- Mobile: 16px above bottom navigation bar + +--- + +## 13. Tailwind Configuration + +Update `tailwind.config.ts` to match this design system: + +```typescript +// Colors to add/update in tailwind.config.ts +colors: { + brand: { + primary: '#00C853', + 'primary-hover': '#00A846', + 'primary-light': '#E8F5E9', + 'primary-dark': '#4ADE80', + secondary: '#0F2A4A', + accent: '#D97706', + }, + // Remove: any amber/gold primary colors + // Remove: any twizrr Green that doesn't match #00C853 +} + +// Fonts to update +fontFamily: { + sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'], + mono: ['JetBrains Mono', 'Roboto Mono', 'monospace'], + // Remove: Outfit, DM Sans, Caveat +} +``` + +--- + +## 14. Animation & Transitions + +| Interaction | Duration | Easing | Property | +|------------|----------|--------|----------| +| Button hover/press | 150ms | ease-out | background-color, transform (scale 0.98) | +| Card hover | 200ms | ease-out | border-color, shadow | +| Page transition | 200ms | ease-in-out | opacity | +| Modal open | 250ms | ease-out | opacity, transform (translateY) | +| Toast notification | 300ms in, 200ms out | ease-out | opacity, transform | +| Skeleton loading | 1.5s loop | ease-in-out | opacity (pulse) | + +### Loading states: +- Use skeleton screens, never spinners +- Skeleton: `bg-tertiary` pulsing rectangles matching expected content shape +- Product feed: show 6 skeleton cards while loading + +--- + +## 15. Accessibility + +- Minimum contrast ratio: 4.5:1 for normal text, 3:1 for large text +- All interactive elements must have visible focus indicators (`border-focus` green) +- All images must have alt text +- Form inputs must have associated labels +- Color must never be the only state indicator — always pair with icons or text +- Keyboard navigation must work for all core flows + +--- + +*This design system supersedes all previous versions. Any references to amber/gold primary colors, Outfit/DM Sans/Caveat fonts, cement, iron, construction, wholesale, RFQ, or industrial aesthetics should be updated to match this document.* diff --git a/README.md b/README.md index d8d409c9..e82bda9c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# Swifta +# twizrr **Nigeria's WhatsApp-Native E-Commerce Platform** Buy and sell anything on WhatsApp with escrow payment protection. Discover products, follow merchants, and shop securely — all from the app you already use. -🌐 **Website:** [swifta.store](https://swifta.store) -📱 **WhatsApp:** Message Swifta to start shopping +🌐 **Website:** [twizrr.com](https://twizrr.com) +📱 **WhatsApp:** Message twizrr to start shopping --- -## What is Swifta? +## What is twizrr? -Swifta is a social commerce marketplace where buyers discover products through a scrollable feed, follow their favorite merchants, and purchase with escrow-protected payments. Merchants list products, manage orders, and get paid instantly to their bank account. +twizrr is a social commerce marketplace where buyers discover products through a scrollable feed, follow their favorite merchants, and purchase with escrow-protected payments. Merchants list products, manage orders, and get paid instantly to their bank account. The platform works on two channels: - **WhatsApp** — the primary channel for buyers. Search, buy, pay, track, and confirm delivery without leaving WhatsApp. @@ -43,7 +43,7 @@ Every transaction is protected by escrow. The buyer's money is held securely unt ### On WhatsApp -Buyers can do everything through the Swifta WhatsApp AI assistant: +Buyers can do everything through the twizrr WhatsApp AI assistant: - **Text search:** "I need a phone case" → get matching products - **Image search:** Send a photo of any product → AI identifies it and finds matches - **Purchase:** Select, pay, track, and confirm — all in the chat @@ -80,7 +80,7 @@ Buyers can do everything through the Swifta WhatsApp AI assistant: ### Architecture ``` -swifta/ +twizrr/ ├── apps/ │ ├── backend/ → NestJS 10 modular API │ └── web/ → Next.js 14 App Router @@ -143,7 +143,7 @@ swifta/ ```bash # Clone the repository git clone -cd swifta +cd twizrr # Install dependencies pnpm install @@ -162,8 +162,8 @@ npx prisma db seed cd ../.. # Start development servers -pnpm --filter @swifta/backend dev # Backend → http://localhost:4000 -pnpm --filter @swifta/web dev # Frontend → http://localhost:3000 +pnpm --filter @twizrr/backend dev # Backend → http://localhost:4000 +pnpm --filter @twizrr/web dev # Frontend → http://localhost:3000 ``` --- diff --git a/apps/backend/Dockerfile b/apps/backend/Dockerfile index 81f12d87..33533ec3 100644 --- a/apps/backend/Dockerfile +++ b/apps/backend/Dockerfile @@ -7,7 +7,7 @@ RUN npm install -g turbo COPY . . -RUN turbo prune --scope=@swifta/backend --docker +RUN turbo prune --scope=@twizrr/backend --docker # ── Stage 2: Install deps + build ── FROM node:20-alpine AS installer @@ -25,7 +25,7 @@ COPY --from=builder /app/out/full/ . RUN npx prisma generate --schema=apps/backend/prisma/schema.prisma # Build backend + shared -RUN pnpm turbo run build --filter=@swifta/backend... +RUN pnpm turbo run build --filter=@twizrr/backend... # ── Stage 3: Slim production runner ── FROM node:20-alpine AS runner diff --git a/apps/backend/README.md b/apps/backend/README.md index cd84f707..be964bed 100644 --- a/apps/backend/README.md +++ b/apps/backend/README.md @@ -1,6 +1,6 @@ -# Swifta — Backend +# twizrr — Backend -NestJS modular monolith API server for Swifta. +NestJS modular monolith API server for twizrr. --- diff --git a/apps/backend/package.json b/apps/backend/package.json index df7e1fa0..4009a9af 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -1,7 +1,7 @@ { - "name": "@swifta/backend", + "name": "@twizrr/backend", "version": "0.0.1", - "description": "Swifta Backend API", + "description": "Twizrr Backend API", "author": "", "private": true, "license": "UNLICENSED", @@ -39,7 +39,7 @@ "@nestjs/throttler": "^6.5.0", "@prisma/adapter-pg": "^7.5.0", "@prisma/client": "^7.5.0", - "@swifta/shared": "workspace:*", + "@twizrr/shared": "workspace:*", "africastalking": "^0.7.9", "bcrypt": "^5.1.1", "bullmq": "^5.69.3", diff --git a/apps/backend/src/common/decorators/roles.decorator.ts b/apps/backend/src/common/decorators/roles.decorator.ts index 2a9bd335..5b1c3a2f 100644 --- a/apps/backend/src/common/decorators/roles.decorator.ts +++ b/apps/backend/src/common/decorators/roles.decorator.ts @@ -1,5 +1,5 @@ import { SetMetadata } from "@nestjs/common"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; export const ROLES_KEY = "roles"; export const Roles = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles); diff --git a/apps/backend/src/common/filters/global-exception.filter.ts b/apps/backend/src/common/filters/global-exception.filter.ts index 1c6f70d5..cd9ef2bd 100644 --- a/apps/backend/src/common/filters/global-exception.filter.ts +++ b/apps/backend/src/common/filters/global-exception.filter.ts @@ -7,7 +7,7 @@ import { Logger, } from "@nestjs/common"; import { Response } from "express"; -import { ApiError } from "@swifta/shared"; +import { ApiError } from "@twizrr/shared"; import * as fs from "fs"; import * as path from "path"; diff --git a/apps/backend/src/common/guards/merchant-verified.guard.ts b/apps/backend/src/common/guards/merchant-verified.guard.ts index 9e1357ac..cc9dc7ce 100644 --- a/apps/backend/src/common/guards/merchant-verified.guard.ts +++ b/apps/backend/src/common/guards/merchant-verified.guard.ts @@ -6,7 +6,7 @@ import { } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; import { PrismaService } from "../../prisma/prisma.service"; -import { VerificationTier } from "@swifta/shared"; +import { VerificationTier } from "@twizrr/shared"; @Injectable() export class MerchantVerifiedGuard implements CanActivate { diff --git a/apps/backend/src/common/guards/roles.guard.ts b/apps/backend/src/common/guards/roles.guard.ts index 126df014..613517a2 100644 --- a/apps/backend/src/common/guards/roles.guard.ts +++ b/apps/backend/src/common/guards/roles.guard.ts @@ -1,6 +1,6 @@ import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { ROLES_KEY } from "../decorators/roles.decorator"; @Injectable() diff --git a/apps/backend/src/common/interceptors/response-transform.interceptor.ts b/apps/backend/src/common/interceptors/response-transform.interceptor.ts index 4198414c..7a3592c9 100644 --- a/apps/backend/src/common/interceptors/response-transform.interceptor.ts +++ b/apps/backend/src/common/interceptors/response-transform.interceptor.ts @@ -6,7 +6,7 @@ import { } from "@nestjs/common"; import { Observable } from "rxjs"; import { map } from "rxjs/operators"; -import { ApiResponse } from "@swifta/shared"; +import { ApiResponse } from "@twizrr/shared"; @Injectable() export class ResponseTransformInterceptor implements NestInterceptor< diff --git a/apps/backend/src/common/middleware/merchant-context.middleware.ts b/apps/backend/src/common/middleware/merchant-context.middleware.ts index b18b861d..2e95bd80 100644 --- a/apps/backend/src/common/middleware/merchant-context.middleware.ts +++ b/apps/backend/src/common/middleware/merchant-context.middleware.ts @@ -1,6 +1,6 @@ import { Injectable, NestMiddleware } from "@nestjs/common"; import { Request, Response, NextFunction } from "express"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; @Injectable() export class MerchantContextMiddleware implements NestMiddleware { diff --git a/apps/backend/src/common/types/express.d.ts b/apps/backend/src/common/types/express.d.ts index f87006ad..038f3b21 100644 --- a/apps/backend/src/common/types/express.d.ts +++ b/apps/backend/src/common/types/express.d.ts @@ -1,4 +1,4 @@ -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; declare global { namespace Express { diff --git a/apps/backend/src/common/utils/pagination.ts b/apps/backend/src/common/utils/pagination.ts index dc0ff14f..ddb595d0 100644 --- a/apps/backend/src/common/utils/pagination.ts +++ b/apps/backend/src/common/utils/pagination.ts @@ -1,4 +1,4 @@ -import { PaginatedResponse } from "@swifta/shared"; +import { PaginatedResponse } from "@twizrr/shared"; export interface PaginationParams { page: number; diff --git a/apps/backend/src/modules/admin/admin-cron.service.ts b/apps/backend/src/modules/admin/admin-cron.service.ts index 69ff42e6..a1958cc1 100644 --- a/apps/backend/src/modules/admin/admin-cron.service.ts +++ b/apps/backend/src/modules/admin/admin-cron.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from "@nestjs/common"; import { Cron, CronExpression } from "@nestjs/schedule"; import { PrismaService } from "../../prisma/prisma.service"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; import { OrderService } from "../order/order.service"; import { NotificationTriggerService } from "../notification/notification-trigger.service"; import { RedisService } from "../../redis/redis.service"; diff --git a/apps/backend/src/modules/admin/admin.controller.ts b/apps/backend/src/modules/admin/admin.controller.ts index 0e5cb9d0..175e649e 100644 --- a/apps/backend/src/modules/admin/admin.controller.ts +++ b/apps/backend/src/modules/admin/admin.controller.ts @@ -15,7 +15,7 @@ import { AdminService } from "./admin.service"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole, OrderStatus } from "@swifta/shared"; +import { UserRole, OrderStatus } from "@twizrr/shared"; import { IsEnum, IsString, IsNotEmpty, IsBoolean, IsIn } from "class-validator"; interface AuthenticatedRequest extends Request { diff --git a/apps/backend/src/modules/admin/admin.service.ts b/apps/backend/src/modules/admin/admin.service.ts index b543444b..80ef5174 100644 --- a/apps/backend/src/modules/admin/admin.service.ts +++ b/apps/backend/src/modules/admin/admin.service.ts @@ -5,7 +5,7 @@ import { Logger, } from "@nestjs/common"; import { PrismaService } from "../../prisma/prisma.service"; -import { OrderStatus, UserRole, VerificationTier } from "@swifta/shared"; +import { OrderStatus, UserRole, VerificationTier } from "@twizrr/shared"; import * as bcrypt from "bcrypt"; import { RedisService } from "../../redis/redis.service"; import { AuditLogService } from "./audit-log.service"; diff --git a/apps/backend/src/modules/admin/audit-log.controller.ts b/apps/backend/src/modules/admin/audit-log.controller.ts index d6818d48..bed08407 100644 --- a/apps/backend/src/modules/admin/audit-log.controller.ts +++ b/apps/backend/src/modules/admin/audit-log.controller.ts @@ -10,7 +10,7 @@ import { AuditLogService } from "./audit-log.service"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; const MAX_LIMIT = 100; diff --git a/apps/backend/src/modules/auth/auth.controller.ts b/apps/backend/src/modules/auth/auth.controller.ts index ce3fe670..92a170d1 100644 --- a/apps/backend/src/modules/auth/auth.controller.ts +++ b/apps/backend/src/modules/auth/auth.controller.ts @@ -25,7 +25,7 @@ import { ResetPasswordDto } from "./dto/reset-password.dto"; import { UpdateProfileDto } from "./dto/update-profile.dto"; import { JwtRefreshGuard } from "../../common/guards/jwt-refresh.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; @Controller("auth") @@ -37,14 +37,14 @@ export class AuthController { tokens: { accessToken: string; refreshToken: string }, ) { const isProd = process.env.NODE_ENV === "production"; - res.cookie("swifta_access_token", tokens.accessToken, { + res.cookie("twizrr_access_token", tokens.accessToken, { httpOnly: true, secure: isProd, sameSite: isProd ? "none" : false, maxAge: 15 * 60 * 1000, path: "/", }); - res.cookie("swifta_refresh_token", tokens.refreshToken, { + res.cookie("twizrr_refresh_token", tokens.refreshToken, { httpOnly: true, secure: isProd, sameSite: isProd ? "none" : false, @@ -61,8 +61,8 @@ export class AuthController { sameSite: isProd ? ("none" as const) : false, path: "/", }; - res.clearCookie("swifta_access_token", cookieOptions); - res.clearCookie("swifta_refresh_token", cookieOptions); + res.clearCookie("twizrr_access_token", cookieOptions); + res.clearCookie("twizrr_refresh_token", cookieOptions); } @Throttle({ default: { limit: 5, ttl: 60000 } }) @@ -179,7 +179,7 @@ export class AuthController { ) { // Prefer HttpOnly cookie first, fallback to DTO body const refreshToken = - (req.cookies as Record)?.["swifta_refresh_token"] || + (req.cookies as Record)?.["twizrr_refresh_token"] || dto.refreshToken; const result = await this.authService.refreshTokens(user.sub, refreshToken); this.setCookies(res, result); diff --git a/apps/backend/src/modules/auth/auth.service.ts b/apps/backend/src/modules/auth/auth.service.ts index 4bee6271..985f3cff 100644 --- a/apps/backend/src/modules/auth/auth.service.ts +++ b/apps/backend/src/modules/auth/auth.service.ts @@ -28,7 +28,7 @@ import { AdminRegisterDto } from "./dto/admin-register.dto"; import { SendPhoneOtpDto } from "./dto/send-phone-otp.dto"; import { VerifyPhoneOtpDto } from "./dto/verify-phone-otp.dto"; import { UpdateProfileDto } from "./dto/update-profile.dto"; -import { TokenPair, JwtPayload } from "@swifta/shared"; +import { TokenPair, JwtPayload } from "@twizrr/shared"; import { WhatsAppService } from "../whatsapp/whatsapp.service"; import { WHATSAPP_OTP_TEMPLATE } from "../whatsapp/whatsapp.constants"; import AfricasTalking from "africastalking"; @@ -715,7 +715,7 @@ export class AuthService { if (this.smsClient) { await this.smsClient.send({ to: [phone], - message: `Your Swifta verification code is ${otp}. It expires in 5 minutes.`, + message: `Your twizrr verification code is ${otp}. It expires in 5 minutes.`, from: this.configService.get("africastalking.senderId"), }); } else { diff --git a/apps/backend/src/modules/auth/dto/register.dto.ts b/apps/backend/src/modules/auth/dto/register.dto.ts index aa6136ff..b0537e49 100644 --- a/apps/backend/src/modules/auth/dto/register.dto.ts +++ b/apps/backend/src/modules/auth/dto/register.dto.ts @@ -6,7 +6,7 @@ import { MinLength, Matches, } from "class-validator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; export class RegisterDto { @IsEmail() diff --git a/apps/backend/src/modules/auth/internal-auth.controller.ts b/apps/backend/src/modules/auth/internal-auth.controller.ts index 3ee9b01b..195ef361 100644 --- a/apps/backend/src/modules/auth/internal-auth.controller.ts +++ b/apps/backend/src/modules/auth/internal-auth.controller.ts @@ -28,14 +28,14 @@ export class InternalAuthController { tokens: { accessToken: string; refreshToken: string }, ) { const isProd = process.env.NODE_ENV === "production"; - res.cookie("swifta_access_token", tokens.accessToken, { + res.cookie("twizrr_access_token", tokens.accessToken, { httpOnly: true, secure: isProd, sameSite: isProd ? "none" : "lax", maxAge: 15 * 60 * 1000, path: "/", }); - res.cookie("swifta_refresh_token", tokens.refreshToken, { + res.cookie("twizrr_refresh_token", tokens.refreshToken, { httpOnly: true, secure: isProd, sameSite: isProd ? "none" : "lax", diff --git a/apps/backend/src/modules/auth/strategies/jwt-access.strategy.ts b/apps/backend/src/modules/auth/strategies/jwt-access.strategy.ts index 280efafe..d6335062 100644 --- a/apps/backend/src/modules/auth/strategies/jwt-access.strategy.ts +++ b/apps/backend/src/modules/auth/strategies/jwt-access.strategy.ts @@ -2,15 +2,15 @@ import { ExtractJwt, Strategy } from "passport-jwt"; import { PassportStrategy } from "@nestjs/passport"; import { Injectable, UnauthorizedException } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; -import { JwtPayload, UserRole } from "@swifta/shared"; +import { JwtPayload, UserRole } from "@twizrr/shared"; import { PrismaService } from "../../../prisma/prisma.service"; import { Request } from "express"; const cookieExtractor = (req: Request): string | null => { let token = null; - if (req && req.cookies && req.cookies["swifta_access_token"]) { - token = req.cookies["swifta_access_token"]; + if (req && req.cookies && req.cookies["twizrr_access_token"]) { + token = req.cookies["twizrr_access_token"]; } // Fallback to Bearer token if (!token && req.headers.authorization) { diff --git a/apps/backend/src/modules/auth/strategies/jwt-refresh.strategy.ts b/apps/backend/src/modules/auth/strategies/jwt-refresh.strategy.ts index 482cc174..b70b96f3 100644 --- a/apps/backend/src/modules/auth/strategies/jwt-refresh.strategy.ts +++ b/apps/backend/src/modules/auth/strategies/jwt-refresh.strategy.ts @@ -7,8 +7,8 @@ import { Request } from "express"; const cookieExtractor = (req: Request): string | null => { let token = null; - if (req && req.cookies && req.cookies["swifta_refresh_token"]) { - token = req.cookies["swifta_refresh_token"]; + if (req && req.cookies && req.cookies["twizrr_refresh_token"]) { + token = req.cookies["twizrr_refresh_token"]; } // Non-production fallback to support easy Postman/Swagger testing without diff --git a/apps/backend/src/modules/buyer/buyer.controller.ts b/apps/backend/src/modules/buyer/buyer.controller.ts index c623994a..66dc42ab 100644 --- a/apps/backend/src/modules/buyer/buyer.controller.ts +++ b/apps/backend/src/modules/buyer/buyer.controller.ts @@ -4,7 +4,7 @@ import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; @Controller("buyer") export class BuyerController { diff --git a/apps/backend/src/modules/cart/cart.controller.ts b/apps/backend/src/modules/cart/cart.controller.ts index 928cd082..673b9119 100644 --- a/apps/backend/src/modules/cart/cart.controller.ts +++ b/apps/backend/src/modules/cart/cart.controller.ts @@ -13,7 +13,7 @@ import { AddToCartDto } from "./dto/add-to-cart.dto"; import { UpdateCartItemDto } from "./dto/update-cart-item.dto"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; @Controller("cart") @UseGuards(JwtAuthGuard) diff --git a/apps/backend/src/modules/cart/cart.service.ts b/apps/backend/src/modules/cart/cart.service.ts index e3d44116..6d5733da 100644 --- a/apps/backend/src/modules/cart/cart.service.ts +++ b/apps/backend/src/modules/cart/cart.service.ts @@ -6,7 +6,7 @@ import { import { PrismaService } from "../../prisma/prisma.service"; import { AddToCartDto } from "./dto/add-to-cart.dto"; import { UpdateCartItemDto } from "./dto/update-cart-item.dto"; -import { PriceType } from "@swifta/shared"; +import { PriceType } from "@twizrr/shared"; @Injectable() export class CartService { diff --git a/apps/backend/src/modules/cart/dto/add-to-cart.dto.ts b/apps/backend/src/modules/cart/dto/add-to-cart.dto.ts index c28aa146..5a457f20 100644 --- a/apps/backend/src/modules/cart/dto/add-to-cart.dto.ts +++ b/apps/backend/src/modules/cart/dto/add-to-cart.dto.ts @@ -7,7 +7,7 @@ import { IsUUID, Min, } from "class-validator"; -import { PriceType } from "@swifta/shared"; +import { PriceType } from "@twizrr/shared"; export class AddToCartDto { @IsString() diff --git a/apps/backend/src/modules/category/category.controller.ts b/apps/backend/src/modules/category/category.controller.ts index d2ed405d..3131c2d3 100644 --- a/apps/backend/src/modules/category/category.controller.ts +++ b/apps/backend/src/modules/category/category.controller.ts @@ -15,7 +15,7 @@ import { UpdateCategoryDto } from "./dto/update-category.dto"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; @Controller("categories") export class CategoryController { diff --git a/apps/backend/src/modules/dva/dva.controller.ts b/apps/backend/src/modules/dva/dva.controller.ts index 2c1ede7c..0d28607d 100644 --- a/apps/backend/src/modules/dva/dva.controller.ts +++ b/apps/backend/src/modules/dva/dva.controller.ts @@ -11,7 +11,7 @@ import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; @Controller("buyer/dva") @UseGuards(JwtAuthGuard, RolesGuard) diff --git a/apps/backend/src/modules/email/email.service.ts b/apps/backend/src/modules/email/email.service.ts index b811de6f..829ef5c4 100644 --- a/apps/backend/src/modules/email/email.service.ts +++ b/apps/backend/src/modules/email/email.service.ts @@ -24,9 +24,9 @@ export class EmailService { this.logger.log(`Sending email to ${to}: ${subject}`); const { data, error } = await this.resend.emails.send({ - from: `Swifta <${this.fromEmail}>`, + from: `twizrr <${this.fromEmail}>`, to: [to], - subject: `Swifta | ${subject}`, + subject: `twizrr | ${subject}`, html, }); @@ -70,12 +70,12 @@ export class EmailService { return `
-

Swifta

+

twizrr

${content}
-

© ${new Date().getFullYear()} Swifta. Built for Lagos trade.

+

© ${new Date().getFullYear()} twizrr. Built for Lagos trade.

@@ -90,9 +90,9 @@ export class EmailService { const safeName = this.escapeHtml(name); const safeRole = this.escapeHtml(role); const content = ` -

Welcome to Swifta, ${safeName}!

+

Welcome to twizrr, ${safeName}!

We're excited to have you on board as a ${safeRole}.

-

Swifta is digitizing Africa's digital trade network, and you're now part of the movement.

+

twizrr is digitizing Africa's digital trade network, and you're now part of the movement.

${ role === "MERCHANT" ? `

Next step: Complete your business profile and start listing your products to receive orders from buyers.

` @@ -102,7 +102,7 @@ export class EmailService { Go to Dashboard `; - await this.sendEmail(to, "Welcome to Swifta", this.getLayout(content)); + await this.sendEmail(to, "Welcome to twizrr", this.getLayout(content)); } async sendVerificationOTP(to: string, otp: string): Promise { @@ -173,7 +173,7 @@ export class EmailService {

Delivery Confirmed Success!

Delivery of Order #${safeReference} has been confirmed.

The transaction of ${this.formatNaira(amountKobo)} is now complete.

-

Thank you for trading with Swifta!

+

Thank you for trading with twizrr!

`; await this.sendEmail( to, @@ -198,7 +198,7 @@ export class EmailService { `; await this.sendEmail( to, - "Reset your Swifta Password", + "Reset your twizrr Password", this.getLayout(content), ); } diff --git a/apps/backend/src/modules/inventory/inventory.controller.ts b/apps/backend/src/modules/inventory/inventory.controller.ts index 42094c15..03253dd5 100644 --- a/apps/backend/src/modules/inventory/inventory.controller.ts +++ b/apps/backend/src/modules/inventory/inventory.controller.ts @@ -15,7 +15,7 @@ import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentMerchant } from "../../common/decorators/current-merchant.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; @Controller("inventory") @UseGuards(JwtAuthGuard, RolesGuard) diff --git a/apps/backend/src/modules/inventory/inventory.service.ts b/apps/backend/src/modules/inventory/inventory.service.ts index e06b1cd1..5f7751d7 100644 --- a/apps/backend/src/modules/inventory/inventory.service.ts +++ b/apps/backend/src/modules/inventory/inventory.service.ts @@ -4,7 +4,7 @@ import { ForbiddenException, } from "@nestjs/common"; import { PrismaService } from "../../prisma/prisma.service"; -import { InventoryEventType } from "@swifta/shared"; +import { InventoryEventType } from "@twizrr/shared"; @Injectable() export class InventoryService { diff --git a/apps/backend/src/modules/logistics/logistics.controller.ts b/apps/backend/src/modules/logistics/logistics.controller.ts index 18e0b164..5604ff23 100644 --- a/apps/backend/src/modules/logistics/logistics.controller.ts +++ b/apps/backend/src/modules/logistics/logistics.controller.ts @@ -13,7 +13,7 @@ import { import * as crypto from "crypto"; import { LogisticsService } from "./logistics.service"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; diff --git a/apps/backend/src/modules/merchant/merchant.controller.ts b/apps/backend/src/modules/merchant/merchant.controller.ts index acd4fdac..2de701d3 100644 --- a/apps/backend/src/modules/merchant/merchant.controller.ts +++ b/apps/backend/src/modules/merchant/merchant.controller.ts @@ -19,7 +19,7 @@ import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { CurrentMerchant } from "../../common/decorators/current-merchant.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; import { MerchantAnalyticsService } from "./merchant-analytics.service"; diff --git a/apps/backend/src/modules/merchant/merchant.service.ts b/apps/backend/src/modules/merchant/merchant.service.ts index 37569d8b..dbef4cdf 100644 --- a/apps/backend/src/modules/merchant/merchant.service.ts +++ b/apps/backend/src/modules/merchant/merchant.service.ts @@ -6,7 +6,7 @@ import { import { PrismaService } from "../../prisma/prisma.service"; import { UpdateMerchantDto } from "./dto/update-merchant.dto"; import { UpdateBankAccountDto } from "./dto/update-bank-account.dto"; -import { UserRole, VerificationTier, maskNin } from "@swifta/shared"; +import { UserRole, VerificationTier, maskNin } from "@twizrr/shared"; import { PaystackClient } from "../payment/paystack.client"; import { NotificationTriggerService } from "../notification/notification-trigger.service"; import { UpdatePreferencesDto } from "./dto/update-preferences.dto"; diff --git a/apps/backend/src/modules/notification/notification-trigger.service.ts b/apps/backend/src/modules/notification/notification-trigger.service.ts index a1b6573f..66bfebea 100644 --- a/apps/backend/src/modules/notification/notification-trigger.service.ts +++ b/apps/backend/src/modules/notification/notification-trigger.service.ts @@ -5,7 +5,7 @@ import { NOTIFICATION_QUEUE, WHATSAPP_QUEUE, } from "../../queue/queue.constants"; -import { NotificationType, NotificationChannel } from "@swifta/shared"; +import { NotificationType, NotificationChannel } from "@twizrr/shared"; @Injectable() export class NotificationTriggerService { @@ -52,7 +52,7 @@ export class NotificationTriggerService { await this.addJob( userId, NotificationType.WELCOME, - "Welcome to Swifta", + "Welcome to twizrr", "Welcome to Africa's digital trade network.", ); } diff --git a/apps/backend/src/modules/notification/notification.controller.ts b/apps/backend/src/modules/notification/notification.controller.ts index 0b35a3ce..1845c478 100644 --- a/apps/backend/src/modules/notification/notification.controller.ts +++ b/apps/backend/src/modules/notification/notification.controller.ts @@ -11,7 +11,7 @@ import { NotificationService } from "./notification.service"; import { PaginationQueryDto } from "../../common/dto/pagination-query.dto"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; @Controller("notifications") @UseGuards(JwtAuthGuard) diff --git a/apps/backend/src/modules/notification/notification.processor.ts b/apps/backend/src/modules/notification/notification.processor.ts index 99755057..7ec54369 100644 --- a/apps/backend/src/modules/notification/notification.processor.ts +++ b/apps/backend/src/modules/notification/notification.processor.ts @@ -5,7 +5,7 @@ import { NOTIFICATION_QUEUE } from "../../queue/queue.constants"; import { PrismaService } from "../../prisma/prisma.service"; import { EmailService } from "../email/email.service"; import { SmsService } from "./sms.service"; -import { NotificationChannel } from "@swifta/shared"; +import { NotificationChannel } from "@twizrr/shared"; @Processor(NOTIFICATION_QUEUE, { concurrency: 5, diff --git a/apps/backend/src/modules/order/dto/checkout-cart.dto.ts b/apps/backend/src/modules/order/dto/checkout-cart.dto.ts index b388e7dc..d5d1b8f0 100644 --- a/apps/backend/src/modules/order/dto/checkout-cart.dto.ts +++ b/apps/backend/src/modules/order/dto/checkout-cart.dto.ts @@ -10,7 +10,7 @@ import { IsObject, } from "class-validator"; -import { PaymentMethod } from "@swifta/shared"; +import { PaymentMethod } from "@twizrr/shared"; export class CheckoutCartDto { @IsArray() diff --git a/apps/backend/src/modules/order/dto/create-tracking.dto.ts b/apps/backend/src/modules/order/dto/create-tracking.dto.ts index cb06997c..8da05516 100644 --- a/apps/backend/src/modules/order/dto/create-tracking.dto.ts +++ b/apps/backend/src/modules/order/dto/create-tracking.dto.ts @@ -1,5 +1,5 @@ import { IsIn, IsString, IsOptional } from "class-validator"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; export class CreateTrackingDto { @IsIn( diff --git a/apps/backend/src/modules/order/invoice.service.ts b/apps/backend/src/modules/order/invoice.service.ts index f1f7a01f..cca7d0a3 100644 --- a/apps/backend/src/modules/order/invoice.service.ts +++ b/apps/backend/src/modules/order/invoice.service.ts @@ -6,7 +6,7 @@ import { import { PrismaService } from "../../prisma/prisma.service"; import PDFDocument from "pdfkit"; import { Response } from "express"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; @Injectable() export class InvoiceService { @@ -66,7 +66,7 @@ export class InvoiceService { doc .fillColor("#444444") .fontSize(20) - .text("Swifta", 50, 45, { align: "left" }) + .text("twizrr", 50, 45, { align: "left" }) .fontSize(10) .text("Digital Marketplace & Escrow Payments", 50, 70, { align: "left" }) .fillColor("#000000") diff --git a/apps/backend/src/modules/order/order-state-machine.ts b/apps/backend/src/modules/order/order-state-machine.ts index 4cde4065..d8d714ca 100644 --- a/apps/backend/src/modules/order/order-state-machine.ts +++ b/apps/backend/src/modules/order/order-state-machine.ts @@ -1,4 +1,4 @@ -import { OrderStatus, ORDER_TRANSITIONS } from "@swifta/shared"; +import { OrderStatus, ORDER_TRANSITIONS } from "@twizrr/shared"; export function validateTransition( from: OrderStatus, diff --git a/apps/backend/src/modules/order/order.controller.ts b/apps/backend/src/modules/order/order.controller.ts index 3d2239c4..e7bbb6eb 100644 --- a/apps/backend/src/modules/order/order.controller.ts +++ b/apps/backend/src/modules/order/order.controller.ts @@ -19,7 +19,7 @@ import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { CurrentMerchant } from "../../common/decorators/current-merchant.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; import { CreateDirectOrderDto } from "./dto/create-direct-order.dto"; import { CreateTrackingDto } from "./dto/create-tracking.dto"; import { CheckoutCartDto } from "./dto/checkout-cart.dto"; diff --git a/apps/backend/src/modules/order/order.service.ts b/apps/backend/src/modules/order/order.service.ts index bd8962c9..d7fc91bc 100644 --- a/apps/backend/src/modules/order/order.service.ts +++ b/apps/backend/src/modules/order/order.service.ts @@ -27,7 +27,7 @@ import { OrderStatus, PaginatedResponse, PriceType, -} from "@swifta/shared"; +} from "@twizrr/shared"; import { paginate } from "../../common/utils/pagination"; import { validateTransition, getNextStates } from "./order-state-machine"; diff --git a/apps/backend/src/modules/payment/payment.controller.ts b/apps/backend/src/modules/payment/payment.controller.ts index c7978947..d6359817 100644 --- a/apps/backend/src/modules/payment/payment.controller.ts +++ b/apps/backend/src/modules/payment/payment.controller.ts @@ -16,7 +16,7 @@ import { WebhookSignatureGuard } from "./webhook-signature.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { IdempotencyKey } from "../../common/decorators/idempotency-key.decorator"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; @Controller("payments") export class PaymentController { diff --git a/apps/backend/src/modules/payment/payment.service.ts b/apps/backend/src/modules/payment/payment.service.ts index 16579f84..db9c4303 100644 --- a/apps/backend/src/modules/payment/payment.service.ts +++ b/apps/backend/src/modules/payment/payment.service.ts @@ -22,7 +22,7 @@ import { PaymentDirection, OrderStatus, UserRole, -} from "@swifta/shared"; +} from "@twizrr/shared"; import * as crypto from "crypto"; import { PAYOUT_QUEUE, LOGISTICS_QUEUE } from "../../queue/queue.constants"; diff --git a/apps/backend/src/modules/payout/payout.service.ts b/apps/backend/src/modules/payout/payout.service.ts index 52042247..c1f1a556 100644 --- a/apps/backend/src/modules/payout/payout.service.ts +++ b/apps/backend/src/modules/payout/payout.service.ts @@ -97,7 +97,7 @@ export class PayoutService { merchant.paystackRecipientCode, payoutAmountKobo, `PO-${order.id.slice(0, 8).toUpperCase()}`, - `Swifta payout for Order #${order.id.slice(0, 8).toUpperCase()}`, + `twizrr payout for Order #${order.id.slice(0, 8).toUpperCase()}`, ); await this.prisma.payout.update({ diff --git a/apps/backend/src/modules/product/product.controller.ts b/apps/backend/src/modules/product/product.controller.ts index 30754fae..40099be4 100644 --- a/apps/backend/src/modules/product/product.controller.ts +++ b/apps/backend/src/modules/product/product.controller.ts @@ -21,7 +21,7 @@ import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { CurrentMerchant } from "../../common/decorators/current-merchant.decorator"; -import { UserRole, JwtPayload } from "@swifta/shared"; +import { UserRole, JwtPayload } from "@twizrr/shared"; @Controller("products") export class ProductController { diff --git a/apps/backend/src/modules/product/product.service.ts b/apps/backend/src/modules/product/product.service.ts index a5ca9c8b..31fc6d5a 100644 --- a/apps/backend/src/modules/product/product.service.ts +++ b/apps/backend/src/modules/product/product.service.ts @@ -11,7 +11,7 @@ import type { Cache } from "cache-manager"; import { PrismaService } from "../../prisma/prisma.service"; import { CreateProductDto } from "./dto/create-product.dto"; import { UpdateProductDto } from "./dto/update-product.dto"; -import { PaginatedResponse, Product } from "@swifta/shared"; +import { PaginatedResponse, Product } from "@twizrr/shared"; import { paginate } from "../../common/utils/pagination"; import { InventoryService } from "../inventory/inventory.service"; diff --git a/apps/backend/src/modules/reorder/reorder.controller.ts b/apps/backend/src/modules/reorder/reorder.controller.ts index 2d822ae7..66f549b1 100644 --- a/apps/backend/src/modules/reorder/reorder.controller.ts +++ b/apps/backend/src/modules/reorder/reorder.controller.ts @@ -9,7 +9,7 @@ import { ReorderService } from "./reorder.service"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; @Controller() @UseGuards(JwtAuthGuard, RolesGuard) diff --git a/apps/backend/src/modules/review/review.controller.ts b/apps/backend/src/modules/review/review.controller.ts index 343494bf..fc6bb743 100644 --- a/apps/backend/src/modules/review/review.controller.ts +++ b/apps/backend/src/modules/review/review.controller.ts @@ -13,7 +13,7 @@ import { CreateReviewDto } from "./dto/create-review.dto"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { OrderService } from "../order/order.service"; -import { JwtPayload } from "@swifta/shared"; +import { JwtPayload } from "@twizrr/shared"; @Controller("reviews") export class ReviewController { diff --git a/apps/backend/src/modules/review/review.service.ts b/apps/backend/src/modules/review/review.service.ts index f60b07a2..9f625abc 100644 --- a/apps/backend/src/modules/review/review.service.ts +++ b/apps/backend/src/modules/review/review.service.ts @@ -8,7 +8,7 @@ import { } from "@nestjs/common"; import { PrismaService } from "../../prisma/prisma.service"; import { CreateReviewDto } from "./dto/create-review.dto"; -import { OrderStatus, VerificationTier } from "@swifta/shared"; +import { OrderStatus, VerificationTier } from "@twizrr/shared"; @Injectable() export class ReviewService { diff --git a/apps/backend/src/modules/supplier/supplier.controller.ts b/apps/backend/src/modules/supplier/supplier.controller.ts index 989bcdba..76a04bc1 100644 --- a/apps/backend/src/modules/supplier/supplier.controller.ts +++ b/apps/backend/src/modules/supplier/supplier.controller.ts @@ -14,7 +14,7 @@ import { CreateWholesaleOrderDto } from "./dto/create-wholesale-order.dto"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; @Controller("supplier") diff --git a/apps/backend/src/modules/supplier/supplier.service.ts b/apps/backend/src/modules/supplier/supplier.service.ts index 4f2d2367..1690d854 100644 --- a/apps/backend/src/modules/supplier/supplier.service.ts +++ b/apps/backend/src/modules/supplier/supplier.service.ts @@ -11,7 +11,7 @@ import { PrismaService } from "../../prisma/prisma.service"; import { CreateSupplierProductDto } from "./dto/create-supplier-product.dto"; import { UpdateSupplierProductDto } from "./dto/update-supplier-product.dto"; import { CreateWholesaleOrderDto } from "./dto/create-wholesale-order.dto"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; import { PaymentService } from "../payment/payment.service"; @Injectable() diff --git a/apps/backend/src/modules/trade-financing/bnpl-partner.interface.ts b/apps/backend/src/modules/trade-financing/bnpl-partner.interface.ts index 9b153db7..04abe6b1 100644 --- a/apps/backend/src/modules/trade-financing/bnpl-partner.interface.ts +++ b/apps/backend/src/modules/trade-financing/bnpl-partner.interface.ts @@ -11,7 +11,7 @@ export interface BuyerCreditData { export interface BnplPartnerClient { /** - * Evaluates the buyer's creditworthiness based on Swifta history + partner logic + * Evaluates the buyer's creditworthiness based on twizrr history + partner logic */ checkEligibility(buyerData: BuyerCreditData): Promise<{ eligible: boolean; @@ -21,7 +21,7 @@ export interface BnplPartnerClient { }>; /** - * Books the loan with the partner. If approved, the partner will disburse funds to Swifta. + * Books the loan with the partner. If approved, the partner will disburse funds to twizrr. */ initiateLoan( orderId: string, diff --git a/apps/backend/src/modules/trade-financing/trade-financing-partner.interface.ts b/apps/backend/src/modules/trade-financing/trade-financing-partner.interface.ts index 9f83e422..df5e9d3a 100644 --- a/apps/backend/src/modules/trade-financing/trade-financing-partner.interface.ts +++ b/apps/backend/src/modules/trade-financing/trade-financing-partner.interface.ts @@ -13,7 +13,7 @@ export interface MerchantCreditData { export interface TradeFinancingPartnerClient { /** - * Evaluates the merchant's creditworthiness based on Swifta sales history + partner logic + * Evaluates the merchant's creditworthiness based on twizrr sales history + partner logic */ checkEligibility(merchantData: MerchantCreditData): Promise<{ eligible: boolean; diff --git a/apps/backend/src/modules/trade-financing/trade-financing.controller.ts b/apps/backend/src/modules/trade-financing/trade-financing.controller.ts index d4420c8b..6aae5003 100644 --- a/apps/backend/src/modules/trade-financing/trade-financing.controller.ts +++ b/apps/backend/src/modules/trade-financing/trade-financing.controller.ts @@ -3,7 +3,7 @@ import { TradeFinancingService } from "./trade-financing.service"; import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { CurrentUser } from "../../common/decorators/current-user.decorator"; import { ApplyLoanDto } from "./dto/apply-loan.dto"; diff --git a/apps/backend/src/modules/upload/upload.controller.ts b/apps/backend/src/modules/upload/upload.controller.ts index 5f9bf7cb..da96bb1e 100644 --- a/apps/backend/src/modules/upload/upload.controller.ts +++ b/apps/backend/src/modules/upload/upload.controller.ts @@ -42,7 +42,7 @@ export class UploadController { try { const url = await this.uploadService.uploadImageToCloudinary( file, - "swifta/documents", + "twizrr/documents", transformType, ); return { @@ -80,7 +80,7 @@ export class UploadController { try { const url = await this.uploadService.uploadImageToCloudinary( file, - "swifta/products", + "twizrr/products", transformType, ); return { diff --git a/apps/backend/src/modules/upload/upload.service.ts b/apps/backend/src/modules/upload/upload.service.ts index 2692a5a0..fe262621 100644 --- a/apps/backend/src/modules/upload/upload.service.ts +++ b/apps/backend/src/modules/upload/upload.service.ts @@ -22,7 +22,7 @@ export class UploadService { async uploadImageToCloudinary( file: Express.Multer.File, - folder: string = "swifta/merchants", + folder: string = "twizrr/merchants", transformType?: string, ): Promise { return new Promise((resolve, reject) => { diff --git a/apps/backend/src/modules/ussd/ussd.service.ts b/apps/backend/src/modules/ussd/ussd.service.ts index 7ab6cda1..2082b082 100644 --- a/apps/backend/src/modules/ussd/ussd.service.ts +++ b/apps/backend/src/modules/ussd/ussd.service.ts @@ -24,7 +24,7 @@ export class UssdService { try { // Level 0: Welcome menu if (level === 0) { - return "CON Welcome to Swifta\n1. Pay for an order\n2. Check order status"; + return "CON Welcome to twizrr\n1. Pay for an order\n2. Check order status"; } const mainChoice = inputs[0]; @@ -52,7 +52,7 @@ export class UssdService { // Level 1: Ask for phone if (level === 1) { - return "CON Enter the phone number linked to your Swifta account:"; + return "CON Enter the phone number linked to your twizrr account:"; } // Level 2: Show pending orders @@ -61,13 +61,13 @@ export class UssdService { const user = await this.prisma.user.findFirst({ where: { phone } }); if (!user) { - return "END No Swifta account found for this number. Visit swifta.store to register."; + return "END No twizrr account found for this number. Visit twizrr.com to register."; } const orders = await this.getPendingOrders(user.id); if (orders.length === 0) { - return "END You have no pending orders. Visit swifta.store to place an order."; + return "END You have no pending orders. Visit twizrr.com to place an order."; } let response = "CON Your pending orders:\n"; @@ -136,7 +136,7 @@ export class UssdService { try { await this.smsService.sendSms( phone, - `Swifta: Complete your payment of N${this.koboToNaira(order.totalAmountKobo)} here: ${paymentData.authorization_url}`, + `twizrr: Complete your payment of N${this.koboToNaira(order.totalAmountKobo)} here: ${paymentData.authorization_url}`, ); } catch (smsErr) { this.logger.warn( @@ -148,7 +148,7 @@ export class UssdService { return [ `END Payment initiated for Order #${shortId}.`, "You will receive a payment link via SMS shortly.", - "Thank you for using Swifta.", + "Thank you for using twizrr.", ].join("\n"); } @@ -164,14 +164,14 @@ export class UssdService { const level = inputs.length; if (level === 1) { - return "CON Enter the phone number linked to your Swifta account:"; + return "CON Enter the phone number linked to your twizrr account:"; } if (level === 2) { const phone = this.toE164(inputs[1]); const user = await this.prisma.user.findFirst({ where: { phone } }); - if (!user) return "END No Swifta account found for this number."; + if (!user) return "END No twizrr account found for this number."; const orders = await this.prisma.order.findMany({ where: { buyerId: user.id }, diff --git a/apps/backend/src/modules/verification/verification.controller.ts b/apps/backend/src/modules/verification/verification.controller.ts index 171658ff..5b125e5b 100644 --- a/apps/backend/src/modules/verification/verification.controller.ts +++ b/apps/backend/src/modules/verification/verification.controller.ts @@ -17,7 +17,7 @@ import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard"; import { RolesGuard } from "../../common/guards/roles.guard"; import { Roles } from "../../common/decorators/roles.decorator"; import { CurrentMerchant } from "../../common/decorators/current-merchant.decorator"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { PaginationQueryDto } from "../../common/dto/pagination-query.dto"; @Controller() diff --git a/apps/backend/src/modules/verification/verification.dto.ts b/apps/backend/src/modules/verification/verification.dto.ts index df024f14..870d62a8 100644 --- a/apps/backend/src/modules/verification/verification.dto.ts +++ b/apps/backend/src/modules/verification/verification.dto.ts @@ -6,7 +6,7 @@ import { IsUrl, IsIn, } from "class-validator"; -import { VerificationIdType } from "@swifta/shared"; +import { VerificationIdType } from "@twizrr/shared"; export class SubmitVerificationDto { @IsUrl({ protocols: ["https"], require_protocol: true }) diff --git a/apps/backend/src/modules/verification/verification.service.ts b/apps/backend/src/modules/verification/verification.service.ts index 3d0982f0..8d0b7a85 100644 --- a/apps/backend/src/modules/verification/verification.service.ts +++ b/apps/backend/src/modules/verification/verification.service.ts @@ -15,7 +15,7 @@ import { OrderStatus, OrderDisputeStatus, NotificationType, -} from "@swifta/shared"; +} from "@twizrr/shared"; @Injectable() export class VerificationService { diff --git a/apps/backend/src/modules/whatsapp/whatsapp-buyer-auth.service.ts b/apps/backend/src/modules/whatsapp/whatsapp-buyer-auth.service.ts index 472b180d..defc6a34 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp-buyer-auth.service.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp-buyer-auth.service.ts @@ -14,14 +14,14 @@ import { OTP_EXPIRED, } from "./whatsapp.constants"; -const BUYER_WELCOME_MESSAGE = `Welcome to Swifta Buyer Bot! 🛒 +const BUYER_WELCOME_MESSAGE = `Welcome to twizrr Buyer Bot! 🛒 To start placing orders natively right here on WhatsApp, please reply with your registered email address to link your buyer profile.`; const BUYER_LINK_SUCCESS = (buyerName: string) => `You're all set, ${buyerName}! 🎉\n\nYou can now tell me what you want to buy, or say "track my order" if you have any active deliveries.`; -const BUYER_ALREADY_LINKED = `This phone number is already linked to a Swifta buyer account.`; +const BUYER_ALREADY_LINKED = `This phone number is already linked to a twizrr buyer account.`; interface SessionData { state: SessionState; diff --git a/apps/backend/src/modules/whatsapp/whatsapp-buyer.constants.ts b/apps/backend/src/modules/whatsapp/whatsapp-buyer.constants.ts index 962359ce..2b8a6c4f 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp-buyer.constants.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp-buyer.constants.ts @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- import { SchemaType, FunctionDeclaration } from "@google/generative-ai"; -export const BUYER_MAIN_MENU = `Welcome to the Swifta Marketplace! ✅ +export const BUYER_MAIN_MENU = `Welcome to the twizrr Marketplace! ✅ I'm your personal shopping assistant. I can help you find products, discover local merchants, and track your deliveries in real-time. @@ -32,7 +32,7 @@ export const BUYER_GEMINI_FUNCTION_DECLARATIONS: FunctionDeclaration[] = [ { name: "search_products", description: - "Search the global Swifta catalogue for a product based on name and optionally location.", + "Search the global twizrr catalogue for a product based on name and optionally location.", parameters: { type: SchemaType.OBJECT, properties: { @@ -57,7 +57,7 @@ export const BUYER_GEMINI_FUNCTION_DECLARATIONS: FunctionDeclaration[] = [ { name: "search_merchants", description: - "Search for verified merchants and shops on Swifta by name or specific location.", + "Search for verified merchants and shops on twizrr by name or specific location.", parameters: { type: SchemaType.OBJECT, properties: { @@ -120,7 +120,7 @@ export const BUYER_GEMINI_FUNCTION_DECLARATIONS: FunctionDeclaration[] = [ { name: "browse_categories", description: - "Browse the available product categories in the Swifta marketplace.", + "Browse the available product categories in the twizrr marketplace.", }, { name: "list_merchant_products", diff --git a/apps/backend/src/modules/whatsapp/whatsapp-buyer.service.ts b/apps/backend/src/modules/whatsapp/whatsapp-buyer.service.ts index 51ead1ab..b389ee28 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp-buyer.service.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp-buyer.service.ts @@ -17,7 +17,7 @@ import { BUYER_MAIN_MENU, BUYER_FRIENDLY_FALLBACK, } from "./whatsapp-buyer.constants"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; import { ReviewService } from "../review/review.service"; import { UploadService } from "../upload/upload.service"; import { ImageSearchService } from "./image-search.service"; @@ -272,7 +272,7 @@ export class WhatsAppBuyerService { await this.redisService.del(checkoutKey); const appUrl = - this.configService.get("FRONTEND_URL") || "https://swifta.store"; + this.configService.get("FRONTEND_URL") || "https://twizrr.com"; const checkoutLink = `${appUrl}/buyer/checkout/${session.productId}?qty=${session.quantity}&delivery=${session.deliveryMethod}`; const dva = await this.getSafeDva(buyerId); @@ -581,7 +581,7 @@ export class WhatsAppBuyerService { if (session.step === "SELECT_DELIVERY") { if (input === "1" || input.toLowerCase().includes("merchant")) { session.deliveryMethod = "MERCHANT_DELIVERY"; - } else if (input === "2" || input.toLowerCase().includes("swifta")) { + } else if (input === "2" || input.toLowerCase().includes("twizrr")) { session.deliveryMethod = "PLATFORM_LOGISTICS"; } else { await this.interactiveService.sendReplyButtons( @@ -597,7 +597,7 @@ export class WhatsAppBuyerService { await this.redisService.del(key); const appUrl = - this.configService.get("FRONTEND_URL") || "https://swifta.store"; + this.configService.get("FRONTEND_URL") || "https://twizrr.com"; const checkoutLink = `${appUrl}/buyer/checkout/${session.productId}?qty=${session.quantity}&delivery=${session.deliveryMethod}`; const dva = await this.getSafeDva(buyerId); @@ -1092,7 +1092,7 @@ export class WhatsAppBuyerService { `${product.name} (${quantity} units)\n\nHow would you like this delivered?`, [ { id: "delivery_merchant", title: "Direct Merchant" }, - { id: "delivery_track", title: "Swifta Tracked" }, + { id: "delivery_track", title: "twizrr Tracked" }, ], product.imageUrl || undefined, ); @@ -1441,7 +1441,7 @@ export class WhatsAppBuyerService { const imageUrl = await this.uploadService.uploadImageToCloudinary( file, - "swifta/reviews", + "twizrr/reviews", ); const order = await this.prisma.order.findUnique({ @@ -1747,7 +1747,7 @@ export class WhatsAppBuyerService { rows: merchants.map((m) => ({ id: `merchant_${m.id}`, title: m.businessName || "Untitled Shop", - description: `${m.averageRating > 0 ? `⭐${m.averageRating.toFixed(1)} | ` : ""}${m.description?.substring(0, 50) || "Verified Swifta Merchant"}`, + description: `${m.averageRating > 0 ? `⭐${m.averageRating.toFixed(1)} | ` : ""}${m.description?.substring(0, 50) || "Verified twizrr Merchant"}`, })), }, ], @@ -1777,7 +1777,7 @@ export class WhatsAppBuyerService { const msg = `🏪 *${merchant.businessName}*\n\n` + - `${merchant.description || "A verified partner on Swifta."}\n\n` + + `${merchant.description || "A verified partner on twizrr."}\n\n` + `📍 *Location:* ${merchant.businessAddress || "Abuja, Nigeria"}\n` + `✨ *Rating:* ${ratingStr}\n\n` + `What would you like to do?`; @@ -1838,7 +1838,7 @@ export class WhatsAppBuyerService { */ private async sendBuyerWelcomeButtons(phone: string): Promise { const welcomeMsg = - `Welcome back to Swifta! 👋\n\n` + + `Welcome back to twizrr! 👋\n\n` + `Secure social commerce for Nigeria. Shop across any category or track your active deliveries.\n\n` + `What would you like to do?`; diff --git a/apps/backend/src/modules/whatsapp/whatsapp-onboarding.service.ts b/apps/backend/src/modules/whatsapp/whatsapp-onboarding.service.ts index 46f3516c..d545df5b 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp-onboarding.service.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp-onboarding.service.ts @@ -153,7 +153,7 @@ export class WhatsAppOnboardingService { private async sendWelcome(phone: string): Promise { await this.interactiveService.sendReplyButtons( phone, - "Welcome to Swifta.\n\nBuy and sell anything on WhatsApp with secure escrow payments. Your money is protected until delivery is confirmed.\n\nHow would you like to get started?", + "Welcome to twizrr.\n\nBuy and sell anything on WhatsApp with secure escrow payments. Your money is protected until delivery is confirmed.\n\nHow would you like to get started?", [ { id: "onboard_buyer", title: "Buy Products" }, { id: "onboard_merchant", title: "Sell Products" }, @@ -165,7 +165,7 @@ export class WhatsAppOnboardingService { private async handleLearnMore(phone: string): Promise { await this.interactiveService.sendReplyButtons( phone, - "Swifta allows you to buy and sell products securely through WhatsApp.\n\nMoney is held safely until you receive your goods. You can track deliveries in real-time and buy from verified merchants. Merchants receive payments directly to their bank account.\n\nReady to get started?", + "twizrr allows you to buy and sell products securely through WhatsApp.\n\nMoney is held safely until you receive your goods. You can track deliveries in real-time and buy from verified merchants. Merchants receive payments directly to their bank account.\n\nReady to get started?", [ { id: "onboard_buyer", title: "Sign Up to Buy" }, { id: "onboard_merchant", title: "Sign Up to Sell" }, @@ -395,7 +395,7 @@ export class WhatsAppOnboardingService { if (existingUser) { await this.interactiveService.sendTextMessage( phone, - "This email is already registered. If you already have a Swifta account, please visit swifta.store to link your WhatsApp number, or use a different email.", + "This email is already registered. If you already have a twizrr account, please visit twizrr.com to link your WhatsApp number, or use a different email.", ); return; } @@ -490,7 +490,7 @@ export class WhatsAppOnboardingService { }); await this.interactiveService.sendTextMessage( phone, - "Too many incorrect attempts. Please visit swifta.store to register instead, or try again later.", + "Too many incorrect attempts. Please visit twizrr.com to register instead, or try again later.", ); return; } @@ -588,7 +588,7 @@ export class WhatsAppOnboardingService { { id: "help", title: "Help", - description: "Learn how Swifta works", + description: "Learn how twizrr works", }, ], }, @@ -605,7 +605,7 @@ export class WhatsAppOnboardingService { }); await this.interactiveService.sendTextMessage( phone, - "This email or phone number is already registered to another account. Please use different details or visit swifta.store.", + "This email or phone number is already registered to another account. Please use different details or visit twizrr.com.", ); return; } @@ -614,7 +614,7 @@ export class WhatsAppOnboardingService { ); await this.interactiveService.sendTextMessage( phone, - "Something went wrong creating your account. Please try again or visit swifta.store to register.", + "Something went wrong creating your account. Please try again or visit twizrr.com to register.", ); } } @@ -775,7 +775,7 @@ export class WhatsAppOnboardingService { if (existingUser) { await this.interactiveService.sendTextMessage( phone, - "This email is already registered. If you already have a Swifta account, please visit swifta.store to link your WhatsApp number, or use a different email.", + "This email is already registered. If you already have a twizrr account, please visit twizrr.com to link your WhatsApp number, or use a different email.", ); return; } @@ -868,7 +868,7 @@ export class WhatsAppOnboardingService { }); await this.interactiveService.sendTextMessage( phone, - "Too many incorrect attempts. Please visit swifta.store to register, or try again later.", + "Too many incorrect attempts. Please visit twizrr.com to register, or try again later.", ); return; } @@ -1274,7 +1274,7 @@ export class WhatsAppOnboardingService { }); await this.interactiveService.sendTextMessage( phone, - "This email or phone number is already registered to another account. Please use different details or visit swifta.store.", + "This email or phone number is already registered to another account. Please use different details or visit twizrr.com.", ); return; } @@ -1283,7 +1283,7 @@ export class WhatsAppOnboardingService { ); await this.interactiveService.sendTextMessage( phone, - "Something went wrong creating your account. Please try again or visit swifta.store to register.", + "Something went wrong creating your account. Please try again or visit twizrr.com to register.", ); } } diff --git a/apps/backend/src/modules/whatsapp/whatsapp-supplier.service.ts b/apps/backend/src/modules/whatsapp/whatsapp-supplier.service.ts index 9cf7230e..c9a1d055 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp-supplier.service.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp-supplier.service.ts @@ -5,7 +5,7 @@ import { WhatsAppSupplierIntentService } from "./whatsapp-supplier-intent.servic import { ParsedIntent } from "./whatsapp-intent.service"; import { RedisService } from "../../redis/redis.service"; import { FRIENDLY_FALLBACK } from "./whatsapp.constants"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; import { WhatsAppInteractiveService } from "./whatsapp-interactive.service"; // Helper to mask phone numbers — only show last 4 digits diff --git a/apps/backend/src/modules/whatsapp/whatsapp.constants.ts b/apps/backend/src/modules/whatsapp/whatsapp.constants.ts index 28607287..83626fb4 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp.constants.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp.constants.ts @@ -12,7 +12,7 @@ export const SUPPLIER_MAIN_MENU = `Supplier Dashboard. Use the menu below to man export const FRIENDLY_FALLBACK = `I did not understand that. Select an option from the menu:`; /** Main menu for buyers */ -export const BUYER_MAIN_MENU = `Welcome to the Swifta Buyer Assistant. Select an option to proceed.`; +export const BUYER_MAIN_MENU = `Welcome to the twizrr Buyer Assistant. Select an option to proceed.`; /** Friendly fallback for buyers */ export const BUYER_FRIENDLY_FALLBACK = `I did not understand that. You can ask: @@ -26,7 +26,7 @@ export const STOCK_UPDATE_FOLLOWUP = `Understood. Which product would you like t Example: "Add 10 pairs of sneakers" or "Remove 5 laptops"`; /** First message for an unlinked phone */ -export const WELCOME_MESSAGE = `Welcome to Swifta. Nigeria's digital marketplace for all your shopping needs. How would you like to use our platform?`; +export const WELCOME_MESSAGE = `Welcome to twizrr. Nigeria's digital marketplace for all your shopping needs. How would you like to use our platform?`; export const ROLE_SELECTED_MESSAGE = `To link your account, please reply with your registered email address.`; diff --git a/apps/backend/src/modules/whatsapp/whatsapp.module.ts b/apps/backend/src/modules/whatsapp/whatsapp.module.ts index c42b7291..fbfcdd6a 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp.module.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp.module.ts @@ -30,7 +30,7 @@ import { WhatsAppLoggerService } from "./whatsapp-logger.service"; * WhatsApp Bot Module * * Integrates with Meta's WhatsApp Business Cloud API to provide - * merchants with a conversational interface to Swifta. + * merchants with a conversational interface to twizrr. * * Dependencies: * - PrismaModule: database access (WhatsAppLink, products, orders, etc.) diff --git a/apps/backend/src/modules/whatsapp/whatsapp.service.ts b/apps/backend/src/modules/whatsapp/whatsapp.service.ts index 31255848..a52c47a8 100644 --- a/apps/backend/src/modules/whatsapp/whatsapp.service.ts +++ b/apps/backend/src/modules/whatsapp/whatsapp.service.ts @@ -23,7 +23,7 @@ import { MENU_BUYER_MODE, MENU_MERCHANT_MODE, } from "./whatsapp.constants"; -import { OrderStatus, VerificationTier } from "@swifta/shared"; +import { OrderStatus, VerificationTier } from "@twizrr/shared"; function maskPhone(phone: string): string { if (!phone) return "unknown"; @@ -310,7 +310,7 @@ export class WhatsAppService { if (id === "menu_help") { await this.interactiveService.sendTextMessage( phone, - `🤝 *Swifta Merchant Support*\n\nYou can manage your business by using the menu or via natural language commands:\n\n• *"sales summary"* - View performance\n• *"my orders"* - Manage latest orders\n• *"check inventory"* - Monitor stock\n• *"update price of [item] to [amount]"*\n• *"add [qty] to [item] stock"*\n\nNeed more help? Visit our web dashboard or contact support at support@swifta.store`, + `🤝 *twizrr Merchant Support*\n\nYou can manage your business by using the menu or via natural language commands:\n\n• *"sales summary"* - View performance\n• *"my orders"* - Manage latest orders\n• *"check inventory"* - Monitor stock\n• *"update price of [item] to [amount]"*\n• *"add [qty] to [item] stock"*\n\nNeed more help? Visit our web dashboard or contact support at support@twizrr.com`, ); return; } @@ -918,7 +918,7 @@ export class WhatsAppService { if (products.length === 0) { await this.interactiveService.sendTextMessage( phone, - "🏪 You have no products listed currently. Please add products via the Swifta web dashboard to begin selling. 🛒", + "🏪 You have no products listed currently. Please add products via the twizrr web dashboard to begin selling. 🛒", ); return; } @@ -1151,13 +1151,13 @@ export class WhatsAppService { let msg = ""; switch (tier) { case VerificationTier.UNVERIFIED: - msg = `Unverified Account. ⚠️\n\nVisit your dashboard settings to complete verification. Verified merchants receive lower fees and higher customer trust.\n\nDashboard: swifta.store/settings`; + msg = `Unverified Account. ⚠️\n\nVisit your dashboard settings to complete verification. Verified merchants receive lower fees and higher customer trust.\n\nDashboard: twizrr.com/settings`; break; case VerificationTier.TIER_1: msg = `Verification Tier: Basic.\n\nUpgrade your status to Verified to enjoy lower platform fees and direct customer payments.`; break; case VerificationTier.TIER_2: - msg = `Account Verified. ✅\n\nYou currently enjoy 1% platform fees and direct customer payments. Thank you for using Swifta.`; + msg = `Account Verified. ✅\n\nYou currently enjoy 1% platform fees and direct customer payments. Thank you for using twizrr.`; break; case VerificationTier.TIER_3: msg = `Trusted Merchant Account. ✅\n\nYou have achieved the highest trust level. You benefit from minimal fees and featured listings.`; @@ -1501,7 +1501,7 @@ export class WhatsAppService { ); await this.interactiveService.sendTextMessage( phone, - `Your Swifta OTP is: ${otpCode}. Please use this to confirm your action.`, + `Your twizrr OTP is: ${otpCode}. Please use this to confirm your action.`, ); // Rethrow to allow upstream SMS fallback if both WhatsApp methods fail throw error; @@ -1698,7 +1698,7 @@ export class WhatsAppService { // Complete - generate app link or pay stack link await this.redisService.del(key); const appUrl = - this.configService.get("FRONTEND_URL") || "https://Swifta.com"; + this.configService.get("FRONTEND_URL") || "https://twizrr.com"; if (paymentMethod === "PAY_NOW") { const merchant = await this.prisma.merchantProfile.findUnique({ @@ -2162,7 +2162,7 @@ export class WhatsAppService { await this.redisService.del(sessionKey); await this.interactiveService.sendTextMessage( phone, - `✅ *Success!* "${data.name}" is now live on Swifta.`, + `✅ *Success!* "${data.name}" is now live on twizrr.`, ); return; } diff --git a/apps/backend/src/prisma/seed.ts b/apps/backend/src/prisma/seed.ts index bb093fd5..548f0d78 100644 --- a/apps/backend/src/prisma/seed.ts +++ b/apps/backend/src/prisma/seed.ts @@ -1,14 +1,14 @@ import "dotenv/config"; import { PrismaClient } from "@prisma/client"; import * as bcrypt from "bcrypt"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; const prisma = new PrismaClient(); async function main() { console.log("🌱 Starting Clean Database Seeding Process..."); - const LEGACY_ADMIN_EMAIL = "admin@swifta.store"; + const LEGACY_ADMIN_EMAIL = "admin@twizrr.com"; const BOOTSTRAP_ADMIN_EMAIL = process.env.ADMIN_BOOTSTRAP_EMAIL || LEGACY_ADMIN_EMAIL; const DEFAULT_ADMIN_PASSWORD = process.env.ADMIN_BOOTSTRAP_PASSWORD; @@ -52,7 +52,7 @@ async function main() { data: { email: BOOTSTRAP_ADMIN_EMAIL, phone: "+234000000000", - firstName: "Swifta", + firstName: "twizrr", lastName: "Admin", passwordHash: passwordHash, role: UserRole.SUPER_ADMIN, @@ -107,7 +107,7 @@ async function main() { await prisma.productAssociation.deleteMany({}); // Optional: Remove the demo merchant user and ALL their data if they exist - const DEMO_MERCHANT_EMAIL = "merchant@demo.swifta.store"; + const DEMO_MERCHANT_EMAIL = "merchant@demo.twizrr.com"; const demoMerchant = await prisma.user.findUnique({ where: { email: DEMO_MERCHANT_EMAIL }, include: { merchantProfile: true }, diff --git a/apps/backend/src/queue/auto-confirm.processor.ts b/apps/backend/src/queue/auto-confirm.processor.ts index e5cabd04..a37b1f78 100644 --- a/apps/backend/src/queue/auto-confirm.processor.ts +++ b/apps/backend/src/queue/auto-confirm.processor.ts @@ -5,7 +5,7 @@ import { AUTO_CONFIRM_QUEUE } from "./queue.constants"; import { PrismaService } from "../prisma/prisma.service"; import { PayoutService } from "../modules/payout/payout.service"; import { WhatsAppService } from "../modules/whatsapp/whatsapp.service"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; const AUTO_CONFIRM_HOURS = 168; // 7 days const REMINDER_3DAYS = 72; @@ -80,7 +80,7 @@ export class AutoConfirmProcessor extends WorkerHost { try { await this.whatsappService.sendWhatsAppMessage( phone, - `⏰ *Delivery Reminder*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* was dispatched 72 hours ago. If it has arrived, please confirm delivery with your OTP code to complete the transaction.\n\nIf there's an issue with delivery, open a dispute via the Swifta app before the payment is released.`, + `⏰ *Delivery Reminder*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* was dispatched 72 hours ago. If it has arrived, please confirm delivery with your OTP code to complete the transaction.\n\nIf there's an issue with delivery, open a dispute via the twizrr app before the payment is released.`, ); } catch (err) { this.logger.warn( @@ -124,7 +124,7 @@ export class AutoConfirmProcessor extends WorkerHost { try { await this.whatsappService.sendWhatsAppMessage( phone, - `⚠️ *Final Reminder — Action Required*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* has been dispatched for 5 days.\n\n*If you do not confirm or dispute within 48 hours, the order will be auto-confirmed and the merchant will be paid automatically.*\n\nPlease confirm delivery with your OTP or open a dispute on the Swifta app.`, + `⚠️ *Final Reminder — Action Required*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* has been dispatched for 5 days.\n\n*If you do not confirm or dispute within 48 hours, the order will be auto-confirmed and the merchant will be paid automatically.*\n\nPlease confirm delivery with your OTP or open a dispute on the twizrr app.`, ); } catch (err) { this.logger.warn( @@ -202,7 +202,7 @@ export class AutoConfirmProcessor extends WorkerHost { try { await this.whatsappService.sendWhatsAppMessage( order.user.phone, - `✅ *Order Auto-Confirmed*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* has been automatically confirmed after ${AUTO_CONFIRM_HOURS} hours.\n\nIf you did not receive your goods, you can open a dispute within the next ${DISPUTE_WINDOW_HOURS} hours via the Swifta app. After that, the payment will be released to the merchant.\n\nThank you for using Swifta! 🙏`, + `✅ *Order Auto-Confirmed*\n\nYour order #${order.id.substring(0, 8)} for *${itemName}* has been automatically confirmed after ${AUTO_CONFIRM_HOURS} hours.\n\nIf you did not receive your goods, you can open a dispute within the next ${DISPUTE_WINDOW_HOURS} hours via the twizrr app. After that, the payment will be released to the merchant.\n\nThank you for using twizrr! 🙏`, ); // Trigger V5 Review Prompt diff --git a/apps/backend/src/queue/checkout-reminder.processor.ts b/apps/backend/src/queue/checkout-reminder.processor.ts index 21fe9906..7d651cbd 100644 --- a/apps/backend/src/queue/checkout-reminder.processor.ts +++ b/apps/backend/src/queue/checkout-reminder.processor.ts @@ -4,7 +4,7 @@ import { Injectable, Logger } from "@nestjs/common"; import { CHECKOUT_REMINDER_QUEUE } from "./queue.constants"; import { PrismaService } from "../prisma/prisma.service"; import { WhatsAppService } from "../modules/whatsapp/whatsapp.service"; -import { OrderStatus } from "@swifta/shared"; +import { OrderStatus } from "@twizrr/shared"; @Injectable() @Processor(CHECKOUT_REMINDER_QUEUE, { @@ -50,7 +50,7 @@ export class CheckoutReminderProcessor extends WorkerHost { const itemName = order.product?.name ?? order.supplierProduct?.name ?? "your items"; - let msg = `🛒 *Checkout Reminder from Swifta*\n\nHi ${order.user.firstName || "there"}! Your order #${order.id.substring(0, 8).toUpperCase()} for *${itemName}* is waiting for payment.\n\n`; + let msg = `🛒 *Checkout Reminder from twizrr*\n\nHi ${order.user.firstName || "there"}! Your order #${order.id.substring(0, 8).toUpperCase()} for *${itemName}* is waiting for payment.\n\n`; const buyerProfile = order.user?.buyerProfile; if (buyerProfile?.dvaActive && buyerProfile?.dvaAccountNumber) { @@ -68,7 +68,7 @@ export class CheckoutReminderProcessor extends WorkerHost { msg += `Please complete your payment using this secure link: ${metadata.checkoutUrl}\n\n`; msg += `This link will finalize your order immediately. ⚡`; } else { - msg += `Please return to the Swifta shop to complete your payment or request a new checkout link from the menu. ⚡`; + msg += `Please return to the twizrr shop to complete your payment or request a new checkout link from the menu. ⚡`; } } diff --git a/apps/backend/test/helpers/test-setup.ts b/apps/backend/test/helpers/test-setup.ts index 0c827ed3..dfba68da 100644 --- a/apps/backend/test/helpers/test-setup.ts +++ b/apps/backend/test/helpers/test-setup.ts @@ -3,7 +3,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { AppModule } from "../../src/app.module"; import { PrismaService } from "../../src/prisma/prisma.service"; import { JwtService } from "@nestjs/jwt"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; export class TestSetup { public app: INestApplication; @@ -29,7 +29,7 @@ export class TestSetup { } async createMockBuyer() { - const email = `test.buyer.${Date.now()}@swifta.store`; + const email = `test.buyer.${Date.now()}@twizrr.com`; const user = await this.prisma.user.create({ data: { email, @@ -54,7 +54,7 @@ export class TestSetup { } async createMockMerchant() { - const email = `test.merchant.${Date.now()}@swifta.store`; + const email = `test.merchant.${Date.now()}@twizrr.com`; const user = await this.prisma.user.create({ data: { email, diff --git a/apps/backend/test/jest-e2e.json b/apps/backend/test/jest-e2e.json index e96b1b0e..4d862f8e 100644 --- a/apps/backend/test/jest-e2e.json +++ b/apps/backend/test/jest-e2e.json @@ -7,6 +7,6 @@ "^.+\\.(t|j)s$": "ts-jest" }, "moduleNameMapper": { - "^@swifta/shared$": "/../../../packages/shared/src" + "^@twizrr/shared$": "/../../../packages/shared/src" } } diff --git a/apps/web/README.md b/apps/web/README.md index 577e97c3..c6c91aa0 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -1,6 +1,6 @@ -# Swifta — Frontend +# twizrr — Frontend -Next.js 14 App Router web application for Swifta. +Next.js 14 App Router web application for twizrr. --- @@ -9,7 +9,7 @@ Next.js 14 App Router web application for Swifta. - **Next.js 14** (App Router) — framework - **TypeScript** — type safety - **Tailwind CSS** — styling -- **@swifta/shared** — shared types, enums, money utilities +- **@twizrr/shared** — shared types, enums, money utilities --- @@ -194,7 +194,7 @@ The API client automatically: All money from the API arrives in **kobo** (integer). Always convert for display: ```typescript -import { formatKobo } from "@swifta/shared"; +import { formatKobo } from "@twizrr/shared"; formatKobo(650000n); // "₦6,500.00" formatKobo(32500000n); // "₦325,000.00" @@ -203,7 +203,7 @@ formatKobo(32500000n); // "₦325,000.00" When user types Naira in forms, convert to kobo before sending to API: ```typescript -import { nairaToKobo } from "@swifta/shared"; +import { nairaToKobo } from "@twizrr/shared"; nairaToKobo(6500); // 650000n ``` diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 3a4a4cc7..2b191880 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -6,7 +6,7 @@ const nextConfig = { images: { domains: ["res.cloudinary.com", "ui-avatars.com"], }, - transpilePackages: ["@swifta/shared"], + transpilePackages: ["@twizrr/shared"], }; export default withSentryConfig( @@ -15,8 +15,8 @@ export default withSentryConfig( // For all available options, see: // https://github.com/getsentry/sentry-webpack-plugin#options silent: true, // Suppresses all logs - org: process.env.SENTRY_ORG || "swifta", - project: process.env.SENTRY_PROJECT || "swifta-frontend", + org: process.env.SENTRY_ORG || "twizrr", + project: process.env.SENTRY_PROJECT || "twizrr-frontend", }, { // For all available options, see: diff --git a/apps/web/package.json b/apps/web/package.json index 15abbf91..07d4a030 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,5 +1,5 @@ { - "name": "@swifta/web", + "name": "@twizrr/web", "version": "1.0.0", "private": true, "scripts": { @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "@swifta/shared": "workspace:*", + "@twizrr/shared": "workspace:*", "@hookform/resolvers": "^5.2.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-slot": "^1.0.2", diff --git a/apps/web/public/manifest.json b/apps/web/public/manifest.json index db609bc1..74433e2d 100644 --- a/apps/web/public/manifest.json +++ b/apps/web/public/manifest.json @@ -1,6 +1,6 @@ { - "name": "Swifta", - "short_name": "Swifta", + "name": "Twizrr", + "short_name": "Twizrr", "description": "Nigeria's WhatsApp E-Commerce Platform", "start_url": "/", "display": "standalone", diff --git a/apps/web/src/app/(auth)/admin/join/page.tsx b/apps/web/src/app/(auth)/admin/join/page.tsx index 3e0fcdf4..49f588ce 100644 --- a/apps/web/src/app/(auth)/admin/join/page.tsx +++ b/apps/web/src/app/(auth)/admin/join/page.tsx @@ -111,7 +111,7 @@ export default function StaffJoinPage() { Internal Operations Portal - Secure administration and operational management for the Swifta + Secure administration and operational management for the twizrr infrastructure.

@@ -279,7 +279,7 @@ export default function StaffJoinPage() { diff --git a/apps/web/src/app/(auth)/admin/login/page.tsx b/apps/web/src/app/(auth)/admin/login/page.tsx index f804006d..4979a297 100644 --- a/apps/web/src/app/(auth)/admin/login/page.tsx +++ b/apps/web/src/app/(auth)/admin/login/page.tsx @@ -11,7 +11,7 @@ import { } from "../../../../lib/validations/auth"; import { useAuth } from "../../../../providers/auth-provider"; import { useToast } from "../../../../providers/toast-provider"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { Logo } from "@/components/ui/logo"; const slides = [ @@ -85,7 +85,7 @@ export default function InternalLoginPage() { > Swifta admin dashboard
@@ -102,7 +102,7 @@ export default function InternalLoginPage() { Internal Operations Portal - Secure administration and operational management for the Swifta + Secure administration and operational management for the twizrr infrastructure.

@@ -189,7 +189,7 @@ export default function InternalLoginPage() { setFormError(null) })} /> diff --git a/apps/web/src/app/(auth)/admin/verify-token/page.tsx b/apps/web/src/app/(auth)/admin/verify-token/page.tsx index 358c8483..c8193a94 100644 --- a/apps/web/src/app/(auth)/admin/verify-token/page.tsx +++ b/apps/web/src/app/(auth)/admin/verify-token/page.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/navigation"; import { authApi } from "../../../../lib/api/auth.api"; import { useAuth } from "../../../../providers/auth-provider"; import { useToast } from "../../../../providers/toast-provider"; -import { getDisplayName } from "@swifta/shared"; +import { getDisplayName } from "@twizrr/shared"; import { Button } from "../../../../components/ui/button"; import { Input } from "../../../../components/ui/input"; import Link from "next/link"; @@ -105,7 +105,7 @@ export default function VerifyTokenPage() { Internal Operations Portal - Secure administration and operational management for the Swifta + Secure administration and operational management for the twizrr infrastructure.

diff --git a/apps/web/src/app/(auth)/login/page.tsx b/apps/web/src/app/(auth)/login/page.tsx index 66ee0f41..07e34292 100644 --- a/apps/web/src/app/(auth)/login/page.tsx +++ b/apps/web/src/app/(auth)/login/page.tsx @@ -8,7 +8,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { loginSchema, type LoginFormData } from "../../../lib/validations/auth"; import { useAuth } from "../../../providers/auth-provider"; import { useToast } from "../../../providers/toast-provider"; -import { UserRole } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; import { useRef } from "react"; import { Logo } from "@/components/ui/logo"; @@ -215,7 +215,7 @@ export default function LoginPage() { > Swifta marketplace
diff --git a/apps/web/src/app/(auth)/register/page.tsx b/apps/web/src/app/(auth)/register/page.tsx index 63e30454..0bebb941 100644 --- a/apps/web/src/app/(auth)/register/page.tsx +++ b/apps/web/src/app/(auth)/register/page.tsx @@ -9,8 +9,8 @@ import { baseRegistrationSchema, type RegistrationFormData, } from "@/lib/validations/auth"; -import { UserRole } from "@swifta/shared"; -import type { RegisterDto } from "@swifta/shared"; +import { UserRole } from "@twizrr/shared"; +import type { RegisterDto } from "@twizrr/shared"; import { useAuth } from "@/providers/auth-provider"; import { useToast } from "@/providers/toast-provider"; import { authApi } from "@/lib/api/auth.api"; @@ -227,7 +227,7 @@ export default function RegisterPage() { > Swifta marketplace
diff --git a/apps/web/src/app/(dashboard)/admin/analytics/page.tsx b/apps/web/src/app/(dashboard)/admin/analytics/page.tsx index b346b6ce..46365536 100644 --- a/apps/web/src/app/(dashboard)/admin/analytics/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/analytics/page.tsx @@ -90,7 +90,7 @@ export default function AdminAnalyticsPage() { link.setAttribute("href", url); link.setAttribute( "download", - `swifta_financials_${new Date().toISOString().split("T")[0]}.csv`, + `twizrr_financials_${new Date().toISOString().split("T")[0]}.csv`, ); document.body.appendChild(link); link.click(); diff --git a/apps/web/src/app/(dashboard)/admin/categories/page.tsx b/apps/web/src/app/(dashboard)/admin/categories/page.tsx index 4e01adfb..107015d5 100644 --- a/apps/web/src/app/(dashboard)/admin/categories/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/categories/page.tsx @@ -7,7 +7,7 @@ import { updateCategory, deleteCategory, } from "@/lib/api/category.api"; -import { type Category } from "@swifta/shared"; +import { type Category } from "@twizrr/shared"; import { Skeleton } from "@/components/ui/skeleton"; import { useToast } from "@/providers/toast-provider"; diff --git a/apps/web/src/app/(dashboard)/admin/settings/page.tsx b/apps/web/src/app/(dashboard)/admin/settings/page.tsx index 15d7ee32..b72eb947 100644 --- a/apps/web/src/app/(dashboard)/admin/settings/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/settings/page.tsx @@ -8,7 +8,7 @@ import * as z from "zod"; import { apiClient } from "@/lib/api-client"; import { useToast } from "@/providers/toast-provider"; import { useAuth } from "@/providers/auth-provider"; -import { getDisplayName } from "@swifta/shared"; +import { getDisplayName } from "@twizrr/shared"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { authApi } from "@/lib/api/auth.api"; diff --git a/apps/web/src/app/(dashboard)/buyer/catalogue/page.tsx b/apps/web/src/app/(dashboard)/buyer/catalogue/page.tsx index d777404f..79f15e2a 100644 --- a/apps/web/src/app/(dashboard)/buyer/catalogue/page.tsx +++ b/apps/web/src/app/(dashboard)/buyer/catalogue/page.tsx @@ -11,7 +11,7 @@ import { type Category, type MerchantProfile, type PaginatedResponse, -} from "@swifta/shared"; +} from "@twizrr/shared"; import { useAuth } from "@/providers/auth-provider"; import { useRouter } from "next/navigation"; diff --git a/apps/web/src/app/(dashboard)/buyer/checkout/[productId]/page.tsx b/apps/web/src/app/(dashboard)/buyer/checkout/[productId]/page.tsx index e626e72c..331ac870 100644 --- a/apps/web/src/app/(dashboard)/buyer/checkout/[productId]/page.tsx +++ b/apps/web/src/app/(dashboard)/buyer/checkout/[productId]/page.tsx @@ -7,7 +7,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { productApi } from "@/lib/api/product.api"; import { createDirectOrder, getDeliveryQuote } from "@/lib/api/order.api"; import { useAuth } from "@/providers/auth-provider"; -import { Product, VerificationTier } from "@swifta/shared"; +import { Product, VerificationTier } from "@twizrr/shared"; import { cn, formatKobo } from "@/lib/utils"; import { StateLgaSelector } from "@/components/ui/state-lga-selector"; @@ -250,7 +250,7 @@ export default function CheckoutPage({ )}>
local_shipping - Swifta Soon + twizrr Soon
diff --git a/apps/web/src/app/(dashboard)/buyer/merchants/page.tsx b/apps/web/src/app/(dashboard)/buyer/merchants/page.tsx index 1fefca7a..a4526c63 100644 --- a/apps/web/src/app/(dashboard)/buyer/merchants/page.tsx +++ b/apps/web/src/app/(dashboard)/buyer/merchants/page.tsx @@ -2,7 +2,7 @@ import { Metadata } from "next"; import { MerchantDiscovery } from "@/components/buyer/merchants/merchant-discovery"; export const metadata: Metadata = { - title: "Merchant Directory | Swifta", + title: "Merchant Directory | twizrr", description: "Find and follow verified merchants.", }; diff --git a/apps/web/src/app/(dashboard)/buyer/notifications/page.tsx b/apps/web/src/app/(dashboard)/buyer/notifications/page.tsx index cdb43807..3e73f488 100644 --- a/apps/web/src/app/(dashboard)/buyer/notifications/page.tsx +++ b/apps/web/src/app/(dashboard)/buyer/notifications/page.tsx @@ -2,7 +2,7 @@ import { Metadata } from "next"; import { NotificationsSharedPage } from "@/components/notifications/notifications-page"; export const metadata: Metadata = { - title: "Notifications | Swifta Buyer", + title: "Notifications | twizrr Buyer", description: "View your recent activities and alerts.", }; diff --git a/apps/web/src/app/(dashboard)/buyer/orders/[id]/page.tsx b/apps/web/src/app/(dashboard)/buyer/orders/[id]/page.tsx index d5bca9ce..cce00437 100644 --- a/apps/web/src/app/(dashboard)/buyer/orders/[id]/page.tsx +++ b/apps/web/src/app/(dashboard)/buyer/orders/[id]/page.tsx @@ -4,7 +4,7 @@ import React, { useState, useMemo } from "react"; import { useParams, useRouter } from "next/navigation"; import Link from "next/link"; import { formatKobo } from "@/lib/utils"; -import type { Order } from "@swifta/shared"; +import type { Order } from "@twizrr/shared"; import { useOrder } from "@/hooks/use-order"; import { OrderTimeline } from "@/components/ui/order-timeline"; import { Modal } from "@/components/ui/modal"; @@ -92,7 +92,7 @@ export default function BuyerOrderDetailsPage() { // Cart checkout if (Array.isArray((order as any).items)) { items.push(...(order as any).items.map((item: any) => ({ - name: item.name || "Swifta Product", + name: item.name || "twizrr Product", sku: `${item.productId?.slice(0, 8)?.toUpperCase() || "GEN"}`, quantity: item.quantity, unitPrice: item.unitPriceKobo, @@ -430,7 +430,7 @@ export default function BuyerOrderDetailsPage() {
Carrier - {order.deliveryMethod === "PLATFORM_LOGISTICS" ? "Swifta Express" : "Merchant Delivery"} + {order.deliveryMethod === "PLATFORM_LOGISTICS" ? "twizrr Express" : "Merchant Delivery"}
@@ -533,7 +533,7 @@ export default function BuyerOrderDetailsPage() { >

- Describe the issue you encountered. The Swifta mediation team will review your report within 24 hours. + Describe the issue you encountered. The twizrr mediation team will review your report within 24 hours.