diff --git a/Org-Feature.md b/Org-Feature.md new file mode 100644 index 0000000..5fcfc64 --- /dev/null +++ b/Org-Feature.md @@ -0,0 +1,450 @@ +# 🏢 Organization Feature — حِرفة + +A complete organization management system that allows craftsmen to form teams, manage bookings under one brand, and operate as a professional services company. + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [How It Works](#how-it-works) +3. [Database Schema](#database-schema) +4. [Pages & Routes](#pages--routes) +5. [Booking Flow](#booking-flow) +6. [Payment Flow](#payment-flow) +7. [Rating System](#rating-system) +8. [Worker Management](#worker-management) +9. [Plan System](#plan-system) +10. [RPC Functions](#rpc-functions) +11. [Migrations](#migrations) + +--- + +## Overview + +The Organization feature transforms Hirfa from a 1-to-1 worker-client platform into a scalable multi-worker business model. A worker can create an organization, recruit other workers under it, and manage all bookings, payments, and ratings through a centralized dashboard. + +### Key Entities + +| Entity | Description | +|--------|-------------| +| **Organization** | A business entity (e.g., "ورشة حكيم الجن وأولاده") owned by a worker | +| **Organization Worker** | A worker linked to an org (may or may not have a linked user account) | +| **Org Booking** | A client booking that goes through the organization | +| **Org Review** | A client review for the organization | + +--- + +## How It Works + +### Lifecycle + +``` +1. Worker creates organization (becomes owner) + ↓ +2. Owner adds workers to the org + ↓ +3. Client browses orgs on home/services → views org profile + ↓ +4. Client books an org service → booking created with organization_id + ↓ +5. Org owner sees booking in dashboard → assigns a worker + ↓ +6. Worker completes job → confirmation code flow + ↓ +7. Payment credited to org owner's wallet + ↓ +8. Client rates → rating goes to both worker AND organization +``` + +### Roles + +| Role | Can Do | +|------|--------| +| **Org Owner** | Create/edit org, add/remove workers, assign workers to bookings, finish jobs, manage wallet | +| **Org Worker** | Complete assigned jobs, see "rating as part of org" on profile | +| **Client** | Browse orgs, view org profile, book org services, rate org | + +--- + +## Database Schema + +### Tables + +#### `organizations` +```sql +id UUID PRIMARY KEY +owner_id UUID NOT NULL → auth.users +name TEXT NOT NULL +description TEXT +category TEXT +city TEXT +logo_url TEXT +plan TEXT DEFAULT 'free' -- 'free' | 'pro' +is_active BOOLEAN DEFAULT true +rating NUMERIC(3,2) DEFAULT 0 +reviews_count INTEGER DEFAULT 0 +worker_count INTEGER DEFAULT 0 +created_at TIMESTAMPTZ +updated_at TIMESTAMPTZ +``` + +#### `organization_workers` +```sql +id UUID PRIMARY KEY +organization_id UUID NOT NULL → organizations (CASCADE) +linked_user_id UUID → auth.users (SET NULL) +display_name TEXT NOT NULL +avatar_url TEXT +phone TEXT +is_active BOOLEAN DEFAULT true +created_at TIMESTAMPTZ +``` + +#### `organization_worker_portfolio` +```sql +id UUID PRIMARY KEY +organization_worker_id UUID NOT NULL → organization_workers (CASCADE) +image_url TEXT NOT NULL +sort_order SMALLINT DEFAULT 0 +created_at TIMESTAMPTZ +``` + +#### `organization_services` +```sql +id UUID PRIMARY KEY +organization_id UUID NOT NULL → organizations (CASCADE) +name TEXT NOT NULL +description TEXT +price NUMERIC +icon TEXT +is_active BOOLEAN DEFAULT true +created_at TIMESTAMPTZ +``` + +#### `organization_gallery` +```sql +id UUID PRIMARY KEY +organization_id UUID NOT NULL → organizations (CASCADE) +image_url TEXT NOT NULL +sort_order SMALLINT DEFAULT 0 +created_at TIMESTAMPTZ +``` + +#### `organization_reviews` +```sql +id UUID PRIMARY KEY +organization_id UUID NOT NULL → organizations (CASCADE) +client_id UUID NOT NULL → auth.users (CASCADE) +booking_id UUID → bookings +rating SMALLINT NOT NULL CHECK (1-5) +text TEXT +created_at TIMESTAMPTZ +``` + +### Bookings Table (Org Columns) + +```sql +-- Added via migration +organization_id UUID → organizations +assigned_worker_id UUID → organization_workers +worker_id UUID → profiles (now nullable) +craftsman_id UUID → profiles (now nullable) +``` + +--- + +## Pages & Routes + +### Client Side + +| Route | Page | Description | +|-------|------|-------------| +| `/client/home` | Home | Shows orgs alongside workers in "حرفيين متميزين" | +| `/client/services/[categoryId]` | Services | Lists orgs and workers for a category | +| `/client/organization/[id]` | Org Profile | Services catalog, portfolio, workers, reviews, booking CTA | +| `/client/booking/[workerId]` | Booking | Supports org mode (detects `organization_id` param) | +| `/client/booking/confirm` | Confirm | Confirms booking (org bookings don't need worker profile) | +| `/client/orders` | Orders | Shows org name + assigned worker name for org bookings | +| `/client/order/invoice` | Invoice | Shows org branding for org bookings | +| `/client/rate-review/[bookingId]` | Rating | Rates org (title: "تقييم المؤسسة") for org bookings | + +### Organization Owner Side + +| Route | Page | Description | +|-------|------|-------------| +| `/organization/home` | Dashboard | Stats (bookings, revenue, pending, completed), recent orders, rating, gallery, quick actions | +| `/organization/orders` | Orders | Full order list with worker assignment UI | +| `/organization/workers` | Workers | Add/remove workers, search linked accounts, portfolio upload | +| `/organization/messages` | Messages | Chat with clients | +| `/organization/wallet` | Wallet | Earnings, transactions, withdrawals | +| `/organization/settings` | Settings | Org settings, services management | + +### Navigation (Bottom Tab Bar) + +``` +المؤسسة | الطلبات | العمال | الرسائل | المحفظة | الإعدادات +Home | Orders | Workers| Messages| Wallet | Settings +``` + +--- + +## Booking Flow + +### 1. Client Books an Organization + +``` +Client selects org service on /client/organization/[id] + ↓ +Client taps "احجز الآن" → /client/booking/[workerId]?organization_id=[orgId] + ↓ +Client selects date, time, address, payment method + ↓ +Client confirms → booking created with: + - organization_id = org.id + - worker_id = null (no specific worker yet) + - service_name = selected service + - status = 'pending' +``` + +### 2. Org Owner Assigns Worker + +``` +Owner sees new booking in /organization/orders + ↓ +Owner taps "تعيين عامل للحجز" + ↓ +Owner searches org workers (from organization_workers table) + ↓ +Owner selects worker → booking updated with: + - assigned_worker_id = org_worker.id + - worker_id = linked_user_id (if worker has a linked account) + ↓ +Notification sent to assigned worker +``` + +### 3. Worker Completes Job + +``` +Assigned worker (or org owner) updates tracking status + ↓ +Worker taps "إنهاء العمل" → finish_job RPC called + ↓ +6-digit confirmation code generated → status = 'awaiting_code_entry' + ↓ +Client shares code with worker → verify_confirmation_code RPC + ↓ +Status = 'completed' → processBookingCompletion() runs +``` + +### 4. Job Completion + +``` +processBookingCompletion(bookingId) + ↓ +Detects organization_id → finds org owner via organizations.owner_id + ↓ +Credits org owner's wallet_balance and total_earnings + ↓ +Inserts transaction with "(مؤسسة)" label +``` + +--- + +## Payment Flow + +### Direct Bookings (No Organization) + +``` +Booking has organization_id = null + ↓ +Payment goes to booking.worker_id's wallet + ↓ +Commission based on worker's subscription tier +``` + +### Organization Bookings + +``` +Booking has organization_id set + ↓ +processBookingCompletion() detects org booking + ↓ +Fetches org owner: organizations.owner_id → profiles + ↓ +Credits OWNER's wallet_balance and total_earnings + ↓ +Commission based on OWNER's subscription tier + ↓ +Transaction logged: "أرباح الطلب #xxx (مؤسسة)" +``` + +### Commission Rates + +| Plan | Commission | Description | +|------|-----------|-------------| +| Free (basic) | 15% | Default for new users | +| Pro | 10% | Professional plan | +| Master | 5% | Master plan | +| Premium | 0% | Premium plan (no commission) | + +--- + +## Rating System + +### Worker Ratings + +- Stored in `reviews` table +- Average computed via `update_worker_rating()` RPC +- Stored on `profiles.rating` + +### Organization Ratings + +- Stored in `organization_reviews` table +- Average auto-computed via trigger `on_org_review_change` +- Stored on `organizations.rating` and `organizations.reviews_count` + +### Auto-Propagation Trigger + +When a worker review is inserted, a database trigger (`on_review_to_org`) checks if the worker belongs to an organization: + +```sql +-- Trigger: on_review_to_org (AFTER INSERT on reviews) +IF craftsman_id exists in organization_workers.linked_user_id + → INSERT INTO organization_reviews (same rating, text, client, booking) + → Existing trigger on_organization_reviews auto-updates org.rating +``` + +This means **one client rating automatically updates both the worker's profile AND the organization's rating**. + +### Worker Profile Display + +Workers who belong to an organization see on their profile: + +``` +┌─────────────────────────────────────────┐ +│ 🏢 تقييم كجزء من المؤسسة │ +│ ورشة حكيم الجن وأولاده ⭐ 4.8 │ +└─────────────────────────────────────────┘ +``` + +Shown on: +- Worker's own profile (`/worker/profile`) +- Worker profile summary (`/worker/profile/summary`) +- Client craftsman page (`/client/craftsman/[id]`) + +--- + +## Worker Management + +### Adding Workers + +1. Owner goes to `/organization/workers` +2. Taps "إضافة عامل" +3. Can search for existing Hirfa users by name or phone +4. If found, links the account (`linked_user_id`) +5. If not found, creates a worker entry with display_name only +6. Worker limit enforced by plan (free: 5, pro: unlimited) + +### Worker Entry Structure + +``` +organization_workers: + id: UUID + organization_id: org.id + linked_user_id: user.id (nullable — worker may not have an account yet) + display_name: "أحمد محمد" + avatar_url: null + phone: "01xxxxxxxxx" + is_active: true + portfolio: [photo1, photo2, photo3, photo4] -- max 4 photos +``` + +### Assigning Workers to Bookings + +In the OrderCard component (`components/ui/orders/OrderCard.tsx`): + +1. Org owner sees a "تعيين عامل للحجز" button for unassigned bookings +2. Tapping opens a worker list fetched from `organization_workers` +3. Owner selects a worker +4. Booking is updated: `assigned_worker_id` set, `worker_id` set to linked user +5. Notification sent to the assigned worker + +--- + +## Plan System + +| Plan | Worker Limit | Features | +|------|-------------|----------| +| **Free** | 5 workers | Basic org features, 15% commission | +| **Pro** | Unlimited | All features, 10% commission | + +### Plan Display + +- Org header card shows plan badge (مجانية / احترافية) +- Worker count shows "X / ∞ عامل" for pro plans +- Upgrade button links to settings + +--- + +## RPC Functions + +### `finish_job(p_booking_id UUID)` + +- Allows org owner to finish jobs (checks `organizations.owner_id = auth.uid()`) +- Generates 6-digit confirmation code +- Sets status to `awaiting_code_entry` +- Uses `md5()` for code generation + +### `verify_confirmation_code(p_booking_id UUID, p_code TEXT)` + +- Allows org owner to verify codes (same owner check pattern) +- Sets status to `completed` +- Returns `{ success: boolean, remaining: number }` + +### `update_worker_rating(p_worker_id UUID)` + +- Recalculates worker average from `reviews` table +- Updates `profiles.rating` + +### `update_org_rating(p_org_id UUID)` + +- Recalculates org average from `organization_reviews` table +- Updates `organizations.rating` and `organizations.reviews_count` +- Auto-triggered by `on_org_review_change` trigger + +--- + +## Migrations + +| Migration | Purpose | +|-----------|---------| +| `20260712010000_org_services_gallery.sql` | Organization services, gallery tables, RLS policies | +| `20260713010000_org_reviews.sql` | Organization reviews table, rating columns, auto-update trigger | +| `20260713020000_make_worker_id_nullable.sql` | Make bookings.worker_id and craftsman_id nullable for org bookings | +| `20260713030000_finish_job_org_owner.sql` | Allow org owner to call finish_job RPC | +| `20260713040000_fix_finish_job_md5.sql` | Fix finish_job to use md5() instead of digest() | +| `20260713050000_fix_verify_code_org_owner.sql` | Allow org owner to verify confirmation codes | +| `20260713060000_review_to_org_trigger.sql` | Auto-propagate worker reviews to organization_reviews | + +--- + +## Key Files + +| File | Purpose | +|------|---------| +| `app/organization/home/page.tsx` | Org dashboard with stats, recent orders, gallery, workers | +| `app/organization/orders/page.tsx` | Org orders page | +| `app/organization/workers/page.tsx` | Workers management (add, search, portfolio) | +| `app/organization/layout.tsx` | Org bottom nav (6 tabs) | +| `app/client/organization/[id]/ClientPage.tsx` | Client-facing org profile | +| `app/client/orders/page.tsx` | Client orders (shows org name + worker) | +| `app/client/order/invoice/page.tsx` | Invoice (org branding for org bookings) | +| `app/client/rate-review/[bookingId]/ClientPage.tsx` | Rating page (org or worker) | +| `components/ui/orders/OrderCard.tsx` | Order card with worker assignment UI | +| `hooks/useOrganization.ts` | Org CRUD, workers, portfolio, plan limits | +| `hooks/useClientBooking.ts` | Booking creation (supports organization_id) | +| `hooks/useOrders.ts` | Fetches both direct and org bookings | +| `lib/supabase/booking-payments.ts` | Payment processing (org owner wallet) | +| `lib/supabase/schema.sql` | Database schema | +| `components/shared/CraftsmanCard.tsx` | Card component (shows orgs + workers) | diff --git a/README.md b/README.md index b9f35b2..379e224 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ ## Overview -Hirfa is a complete home maintenance platform built with Next.js 16 and Supabase. It serves two user types: +Hirfa is a complete home maintenance platform built with Next.js 16 and Supabase. It serves three user types: -- **Clients** — Browse craftsmen, book services, request emergency help, manage orders and wallet +- **Clients** — Browse craftsmen and organizations, book services, request emergency help, manage orders and wallet - **Craftsmen (Workers)** — Manage gallery with before/after photos, accept/reject orders, set services, manage schedule and payments +- **Organizations** — Manage a team of craftsmen under one brand, handle org bookings, assign workers, manage services and portfolio --- @@ -25,19 +26,22 @@ Hirfa is a complete home maintenance platform built with Next.js 16 and Supabase ### Client App -| Feature | Description | -| --------------------- | ---------------------------------------------------------------------- | -| **Home** | Category grid, featured craftsmen, nearby listings | -| **Craftsman Profile** | Full profile with before/after gallery, services, reviews, booking CTA | -| **Gallery Modal** | Card-based photo viewer with navigation (before/after comparison) | -| **Booking** | 4-step wizard with date picker, time slots, address, payment method | -| **Emergency SOS** | Quick emergency booking with live tracking simulation | -| **Orders** | Track order status (pending → confirmed → completed) | -| **Wallet** | Deposit, cards management, transaction history | -| **Addresses** | Saved addresses with CRUD | -| **Search** | Search craftsmen by name or profession | -| **Notifications** | Real-time notifications | -| **Profile** | Edit personal info, settings menu | +| Feature | Description | +| ------------------------ | ---------------------------------------------------------------------- | +| **Home** | Category grid, featured craftsmen & organizations, nearby listings | +| **Craftsman Profile** | Full profile with before/after gallery, services, reviews, booking CTA | +| **Organization Profile** | Org profile with services catalog, portfolio gallery, workers, reviews | +| **Gallery Modal** | Card-based photo viewer with navigation (before/after comparison) | +| **Booking** | 4-step wizard with date picker, time slots, address, payment method | +| **Emergency SOS** | Quick emergency booking with live tracking simulation | +| **Orders** | Track orders — shows org name + worker name for org bookings | +| **Invoice** | Final invoice with org branding for org bookings | +| **Rating** | Rate workers or organizations after completion | +| **Wallet** | Deposit, cards management, transaction history | +| **Addresses** | Saved addresses with CRUD | +| **Search** | Search craftsmen by name or profession | +| **Notifications** | Real-time notifications | +| **Profile** | Edit personal info, settings menu | ### 🔧 Craftsman (Worker) App @@ -53,6 +57,23 @@ Hirfa is a complete home maintenance platform built with Next.js 16 and Supabase | **Profile** | Edit info, verification status, payment methods, help, terms | | **Wallet** | Earnings overview, withdrawals | | **Calendar** | View booked appointments | +| **Org Rating** | Rating as part of an organization shown on profile | + +### 🏢 Organization App + +| Feature | Description | +| -------------------------- | -------------------------------------------------------------------------------- | +| **Dashboard** | Real-time stats (bookings, revenue, pending/completed), recent orders, rating | +| **Orders Management** | View all org bookings, accept/reject, assign workers, update tracking status | +| **Worker Assignment** | Assign org workers to bookings, search linked accounts, send notifications | +| **Workers Management** | Dedicated workers page — add, remove, search linked accounts, portfolio upload | +| **Services Management** | Manage org services and pricing | +| **Portfolio Gallery** | Upload/remove org portfolio photos (up to 5) | +| **Organization Profile** | Create/edit org with name, category, city, logo, description | +| **Plan System** | Free plan with worker limits, Pro plan for unlimited workers | +| **Wallet** | Org wallet with earnings, withdrawals, transaction history | +| **Messages** | Chat with clients | +| **Settings** | Org settings and configuration | ### Admin Dashboard @@ -60,6 +81,58 @@ Hirfa is a complete home maintenance platform built with Next.js 16 and Supabase --- +## 🏢 Organization System + +The platform supports a full organization management system where craftsmen can form organizations and manage teams. + +### How It Works + +1. **Worker creates an organization** via their profile → becomes the owner +2. **Owner adds workers** to the org (search by name/phone, link accounts) +3. **Clients browse** organizations alongside individual craftsmen +4. **Client books an org** → order appears in the org's dashboard +5. **Owner assigns a worker** to the booking +6. **Worker completes the job** → confirmation code flow +7. **Payment goes to the org owner's wallet** (not the individual worker) +8. **Client rates** → rating goes to both the worker and the organization + +### Key Components + +| Component | Description | +| ------------------------- | ------------------------------------------------------------------------ | +| **Org Profile (Client)** | Services catalog, portfolio gallery (5 photos), workers list, reviews | +| **Org Dashboard (Owner)** | Stats grid, recent orders, gallery management, quick actions | +| **Org Orders** | Full order list with worker assignment, tracking updates, status badges | +| **Org Workers** | Add/remove workers, search linked accounts, portfolio upload (4 photos) | +| **Org Wallet** | Earnings from all org bookings, transaction history, withdrawals | +| **Org Booking Flow** | Client selects org service → default schedule → org owner assigns worker | + +### Database + +- `organizations` — org profile with name, category, city, logo, plan, rating +- `organization_workers` — workers linked to an org (linked_user_id → auth.users) +- `organization_worker_portfolio` — portfolio photos per worker +- `organization_reviews` — client reviews for the org (auto-updated via trigger) +- `organization_gallery` — org portfolio photos +- `organization_services` — services offered by the org +- Bookings link to org via `organization_id` and `assigned_worker_id` + +### Rating System + +- Worker ratings: stored in `reviews` table, average on `profiles.rating` +- Org ratings: stored in `organization_reviews` table, average on `organizations.rating` +- **Auto-propagation**: when a worker review is inserted and the worker belongs to an org, a database trigger automatically inserts an org review — keeping org ratings in sync +- Workers see "تقييم كجزء من المؤسسة" (rating as part of organization) on their profile + +### Payment Flow + +- **Direct bookings**: money goes to the worker's wallet +- **Org bookings**: money goes to the org owner's wallet +- Commission rate determined by the recipient's subscription tier +- Transactions logged with `(مؤسسة)` label for org bookings + +--- + ## Tech Stack | Layer | Technology | @@ -89,6 +162,21 @@ Hirfa/ │ ├── admin/ # Admin dashboard │ ├── api/ # Supabase API routes │ ├── client/ # Client pages (craftsman, booking, wallet, etc.) +│ │ ├── organization/ # Org profile page (client view) +│ │ ├── craftsman/ # Worker profile page (client view) +│ │ ├── booking/ # Booking flow (individual & org) +│ │ ├── orders/ # Client orders list +│ │ ├── order/ # Order detail, invoice, success +│ │ ├── rate-review/ # Rating page (workers & orgs) +│ │ ├── services/ # Category services listing +│ │ └── ... +│ ├── organization/ # Org owner dashboard +│ │ ├── home/ # Dashboard with stats, orders, gallery +│ │ ├── orders/ # Org orders with worker assignment +│ │ ├── workers/ # Workers management (add, search, portfolio) +│ │ ├── messages/ # Org messages +│ │ ├── wallet/ # Org wallet & earnings +│ │ └── settings/ # Org settings │ ├── globals.css # Global styles + design tokens │ ├── layout.tsx # Root layout with RTL and fonts │ └── page.tsx # Splash redirect @@ -96,9 +184,13 @@ Hirfa/ │ ├── auth/ # ProtectedRoute, Route guards │ ├── shared/ # CraftsmanCard, CategoryCard, OTPInput │ └── ui/ # BeforeAfterCard, ImageUploader, modals, etc. +│ ├── orders/ # OrderCard, OrdersTabs (supports org bookings) +│ ├── profile/ # StatCard, ReviewCard, MenuGroup, etc. +│ └── wallet/ # WalletBalanceCard, TransactionCard ├── contexts/ # AuthContext -├── hooks/ # useGallery, useCraftsmanProfile, etc. +├── hooks/ # useGallery, useCraftsmanProfile, useOrganization, etc. ├── lib/ # Types, utils, Supabase client/server +│ └── supabase/ # booking-payments.ts (handles org payments) ├── services/ # Auth and profile services ├── supabase/ # Migrations, schema └── public/ # Static assets diff --git a/app/client/organization/[id]/ClientPage.tsx b/app/client/organization/[id]/ClientPage.tsx index 2119cb3..14e27a4 100644 --- a/app/client/organization/[id]/ClientPage.tsx +++ b/app/client/organization/[id]/ClientPage.tsx @@ -173,8 +173,10 @@ export default function OrgProfilePage({ id }: { id: string }) {
عمال
{org.services.length}
+{org.services.length}
+خدمات