Menu

Change language

GitHub repo

Airbnb Host Earnings

blockreal-estate

Short-term rental host revenue dashboard: gross earnings with month-over-month growth, occupancy rate progress, ADR & RevPAR metrics, automated direct deposit payout schedule card, dynamic pricing AI rate recommendations, and an itemized reservation payout breakdown table.

Installation

$npx uipkge-ng@latest add airbnb-host-earnings
Manifest:https://uipkge.dev/r/angular/airbnb-host-earnings.jsonInstalls to:src/app/components/blocks/airbnb-host-earnings/

Variants

Loading interactive previews…

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

ReservationGuest
interface ReservationGuest {
  name: string
  avatar: string
  initials: string
}
ReservationPayout
interface ReservationPayout {
  id: string
  confirmationCode: string
  guest: ReservationGuest
  property: string
  location: string
  datesBooked: string
  nightsCount: number
  nightlyRate: string
  cleaningFee: string
  hostServiceFee: string
  netPayout: string
  status: ReservationPayoutStatus
}

Files installed (2)

  • src/app/components/blocks/airbnb-host-earnings/airbnb-host-earnings.component.ts27.8 kB
    // Short-term rental host revenue dashboard: gross earnings, occupancy rate,
    // ADR & RevPAR metrics, payout schedule, dynamic pricing suggestions, and an
    // itemized reservation payout table. Port of the React block 1:1.
    import { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core'
    import {
      Building2,
      Calendar,
      CalendarCheck,
      Check,
      CheckCircle2,
      Clock,
      DollarSign,
      Download,
      Home,
      Landmark,
      LucideAngularModule,
      TrendingUp,
    } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiAvatarComponent, UiAvatarFallbackComponent, UiAvatarImageComponent } from '@/ui/avatar/avatar.component'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiButtonComponent } from '@/ui/button/button.component'
    import {
      UiCardComponent,
      UiCardContentComponent,
      UiCardDescriptionComponent,
      UiCardHeaderComponent,
      UiCardTitleComponent,
    } from '@/ui/card/card.component'
    import { UiProgressComponent } from '@/ui/progress/progress.component'
    import {
      UiSelectComponent,
      UiSelectContentComponent,
      UiSelectItemComponent,
      UiSelectTriggerComponent,
      UiSelectValueComponent,
    } from '@/ui/select/select.component'
    import {
      UiTableBodyComponent,
      UiTableCellComponent,
      UiTableComponent,
      UiTableHeadComponent,
      UiTableHeaderComponent,
      UiTableRowComponent,
    } from '@/ui/table/table.component'
    
    export type ReservationPayoutStatus = 'paid' | 'processing'
    
    export interface ReservationGuest {
      name: string
      avatar: string
      initials: string
    }
    
    export interface ReservationPayout {
      id: string
      confirmationCode: string
      guest: ReservationGuest
      property: string
      location: string
      datesBooked: string
      nightsCount: number
      nightlyRate: string
      cleaningFee: string
      hostServiceFee: string
      netPayout: string
      status: ReservationPayoutStatus
    }
    
    const reservations: ReservationPayout[] = [
      {
        id: 'res-1',
        confirmationCode: 'HM-8924A',
        guest: {
          name: 'Sophia Martinez',
          avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&auto=format&fit=crop&q=80',
          initials: 'SM',
        },
        property: 'Malibu Beachfront Villa',
        location: 'Malibu, CA',
        datesBooked: 'Aug 18-24 (6 nights)',
        nightsCount: 6,
        nightlyRate: '$650.00',
        cleaningFee: '$350.00',
        hostServiceFee: '-$127.50',
        netPayout: '$4,122.50',
        status: 'paid',
      },
      {
        id: 'res-2',
        confirmationCode: 'HM-8919B',
        guest: {
          name: 'David Kim',
          avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&auto=format&fit=crop&q=80',
          initials: 'DK',
        },
        property: 'Aspen Luxury Chalet',
        location: 'Aspen, CO',
        datesBooked: 'Aug 12-16 (4 nights)',
        nightsCount: 4,
        nightlyRate: '$720.00',
        cleaningFee: '$250.00',
        hostServiceFee: '-$94.00',
        netPayout: '$3,036.00',
        status: 'paid',
      },
      {
        id: 'res-3',
        confirmationCode: 'HM-8912C',
        guest: {
          name: 'Elena Rostova',
          avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&auto=format&fit=crop&q=80',
          initials: 'ER',
        },
        property: 'Maui Oceanfront Suite',
        location: 'Maui, HI',
        datesBooked: 'Aug 04-10 (6 nights)',
        nightsCount: 6,
        nightlyRate: '$580.00',
        cleaningFee: '$300.00',
        hostServiceFee: '-$113.40',
        netPayout: '$3,666.60',
        status: 'paid',
      },
      {
        id: 'res-4',
        confirmationCode: 'HM-8931D',
        guest: {
          name: 'Marcus Vance',
          avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=150&auto=format&fit=crop&q=80',
          initials: 'MV',
        },
        property: 'Malibu Beachfront Villa',
        location: 'Malibu, CA',
        datesBooked: 'Aug 25-31 (6 nights)',
        nightsCount: 6,
        nightlyRate: '$690.00',
        cleaningFee: '$350.00',
        hostServiceFee: '-$134.70',
        netPayout: '$4,355.30',
        status: 'processing',
      },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-airbnb-host-earnings, [ui-airbnb-host-earnings]',
      standalone: true,
      // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.
      host: { '[attr.class]': '"contents"' },
      imports: [
        LucideAngularModule,
        UiAvatarComponent,
        UiAvatarFallbackComponent,
        UiAvatarImageComponent,
        UiBadgeComponent,
        UiButtonComponent,
        UiCardComponent,
        UiCardContentComponent,
        UiCardDescriptionComponent,
        UiCardHeaderComponent,
        UiCardTitleComponent,
        UiProgressComponent,
        UiSelectComponent,
        UiSelectContentComponent,
        UiSelectItemComponent,
        UiSelectTriggerComponent,
        UiSelectValueComponent,
        UiTableBodyComponent,
        UiTableCellComponent,
        UiTableComponent,
        UiTableHeadComponent,
        UiTableHeaderComponent,
        UiTableRowComponent,
      ],
      template: `
        <div data-slot="airbnb-host-earnings" [class]="rootClass">
          <!-- Header Section -->
          <div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
            <div class="space-y-1">
              <h1 class="text-foreground text-2xl font-bold tracking-tight sm:text-3xl">
                Host Earnings & Revenue Analytics
              </h1>
              <p class="text-muted-foreground text-sm">
                Short-term rental portfolio revenue, occupancy yield metrics, and automated payout disbursement schedule.
              </p>
            </div>
            <div class="flex flex-wrap items-center gap-2.5">
              <ui-select [value]="selectedProperty()" (valueChange)="selectedProperty.set($event)">
                <button ui-select-trigger class="w-48 text-xs" aria-label="Select property">
                  <lucide-icon [img]="Home" class="text-muted-foreground mr-1.5 size-3.5" />
                  <ui-select-value placeholder="Select property" />
                </button>
                <ui-select-content>
                  <ui-select-item value="all">All Properties (3)</ui-select-item>
                  <ui-select-item value="malibu">Malibu Beachfront Villa</ui-select-item>
                  <ui-select-item value="aspen">Aspen Luxury Chalet</ui-select-item>
                  <ui-select-item value="maui">Maui Oceanfront Suite</ui-select-item>
                </ui-select-content>
              </ui-select>
    
              <ui-select [value]="selectedTimeframe()" (valueChange)="selectedTimeframe.set($event)">
                <button ui-select-trigger class="w-52 text-xs" aria-label="Select timeframe">
                  <lucide-icon [img]="Calendar" class="text-muted-foreground mr-1.5 size-3.5" />
                  <ui-select-value placeholder="Select timeframe" />
                </button>
                <ui-select-content>
                  <ui-select-item value="this-month">This Month · August 2026</ui-select-item>
                  <ui-select-item value="last-month">Last Month · July 2026</ui-select-item>
                  <ui-select-item value="q3">Last 90 Days (Peak Summer)</ui-select-item>
                  <ui-select-item value="ytd">Year to Date · 2026</ui-select-item>
                </ui-select-content>
              </ui-select>
    
              <button ui-button aria-label="Download attachment" variant="outline" size="sm" class="gap-1.5 text-xs">
                <lucide-icon [img]="Download" class="size-3.5" />
                <span>Export Tax 1099 CSV</span>
              </button>
            </div>
          </div>
    
          <!-- 4 Primary Host KPI Cards -->
          <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header class="pb-2">
                <div class="flex items-center justify-between gap-2">
                  <div class="flex flex-wrap items-center gap-2">
                    <div
                      class="border-success/20 bg-success/10 text-success flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs"
                      aria-hidden="true"
                    >
                      <lucide-icon [img]="DollarSign" class="size-4" />
                    </div>
                    <h3 ui-card-title class="text-muted-foreground text-sm font-medium">Gross Earnings</h3>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-success/20 bg-success/10 text-success text-xs font-bold tabular-nums"
                  >
                    +14.2% vs last month
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-3">
                <div>
                  <div class="flex items-baseline gap-1.5">
                    <span class="text-foreground text-2xl font-bold tracking-tight tabular-nums">$18,450.00</span>
                  </div>
                  <p class="text-muted-foreground mt-0.5 text-xs">Net after 3% fee: $17,896.50</p>
                </div>
                <div class="border-border/60 border-t pt-2 text-xs">
                  <div class="flex items-center justify-between">
                    <span class="text-muted-foreground">Projected month-end:</span>
                    <span class="text-foreground font-semibold tabular-nums">$21,400.00</span>
                  </div>
                </div>
              </div>
            </div>
    
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header class="pb-2">
                <div class="flex items-center justify-between gap-2">
                  <div class="flex flex-wrap items-center gap-2">
                    <div
                      class="border-border bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs"
                      aria-hidden="true"
                    >
                      <lucide-icon [img]="CalendarCheck" class="size-4" />
                    </div>
                    <h3 ui-card-title class="text-muted-foreground text-sm font-medium">Occupancy Rate</h3>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-success/20 bg-success/10 text-success text-xs font-bold tabular-nums"
                  >
                    +6.2% vs area avg
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-3">
                <div>
                  <div class="flex items-baseline gap-1.5">
                    <span class="text-foreground text-2xl font-bold tracking-tight tabular-nums">88.5%</span>
                  </div>
                  <p class="text-muted-foreground mt-0.5 text-xs tabular-nums">27 of 31 nights booked</p>
                </div>
                <div class="space-y-1.5">
                  <ui-progress
                    [value]="88.5"
                    class="[&_[data-slot=progress-indicator]]:bg-success dark:[&_[data-slot=progress-indicator]]:bg-success h-1.5"
                  />
                  <div class="text-muted-foreground flex items-center justify-between text-xs tabular-nums">
                    <span>4 nights open</span>
                    <span>2 instant holds</span>
                  </div>
                </div>
              </div>
            </div>
    
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header class="pb-2">
                <div class="flex items-center justify-between gap-2">
                  <div class="flex flex-wrap items-center gap-2">
                    <div
                      class="border-border bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs"
                      aria-hidden="true"
                    >
                      <lucide-icon [img]="TrendingUp" class="size-4" />
                    </div>
                    <h3 ui-card-title class="text-muted-foreground text-sm font-medium">Average Daily Rate (ADR)</h3>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-success/20 bg-success/10 text-success text-xs font-medium tabular-nums"
                  >
                    +$45.00 vs baseline
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-3">
                <div>
                  <div class="flex items-baseline gap-1">
                    <span class="text-foreground text-2xl font-bold tracking-tight tabular-nums">$683.33</span>
                    <span class="text-muted-foreground text-xs font-normal">/ night</span>
                  </div>
                  <p class="text-muted-foreground mt-0.5 text-xs">Blended across active portfolio</p>
                </div>
                <div class="border-border/60 border-t pt-2 text-xs">
                  <div class="flex items-center justify-between">
                    <span class="text-muted-foreground">Weekend surge rate:</span>
                    <span class="text-foreground font-semibold tabular-nums">$820.00 / night</span>
                  </div>
                </div>
              </div>
            </div>
    
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header class="pb-2">
                <div class="flex items-center justify-between gap-2">
                  <div class="flex flex-wrap items-center gap-2">
                    <div
                      class="border-border bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs"
                      aria-hidden="true"
                    >
                      <lucide-icon [img]="Building2" class="size-4" />
                    </div>
                    <h3 ui-card-title class="text-muted-foreground text-sm font-medium">RevPAR (Yield / Unit)</h3>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-success/20 bg-success/10 text-success text-xs font-bold tabular-nums"
                  >
                    +18.4% YoY
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-3">
                <div>
                  <div class="flex items-baseline gap-1.5">
                    <span class="text-foreground text-2xl font-bold tracking-tight tabular-nums">$604.75</span>
                  </div>
                  <p class="text-muted-foreground mt-0.5 text-xs tabular-nums">Market benchmark: $512.00</p>
                </div>
                <div class="border-border/60 border-t pt-2 text-xs">
                  <div class="flex items-center justify-between">
                    <span class="text-muted-foreground">Regional yield index:</span>
                    <span class="text-success font-semibold">Top 5% in submarket</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
    
          <!-- Middle Grid: Upcoming Payouts Schedule & Dynamic Pricing Suggestions -->
          <div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header>
                <div class="flex items-center justify-between">
                  <div class="space-y-1">
                    <h3 ui-card-title>Upcoming Payouts Schedule</h3>
                    <p ui-card-description>
                      Automated direct deposits sent to your verified checking account 24 hours post check-in.
                    </p>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-success/20 bg-success/10 text-success text-xs font-medium"
                  >
                    <lucide-icon [img]="CheckCircle2" class="mr-1 size-3" />
                    Auto-Transfer Active
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-4">
                <div class="border-border bg-muted/40 rounded-lg border p-4">
                  <div class="flex items-start justify-between gap-4">
                    <div class="flex items-start gap-3">
                      <div
                        class="border-success/20 bg-success/10 text-success flex size-9 shrink-0 items-center justify-center rounded-lg border"
                      >
                        <lucide-icon [img]="Landmark" class="size-4.5" />
                      </div>
                      <div class="space-y-0.5">
                        <span class="text-muted-foreground text-xs font-medium tracking-wider uppercase">Next Payout</span>
                        <div class="text-foreground text-2xl font-bold tracking-tight tabular-nums">$4,250.00</div>
                        <p class="text-foreground text-xs font-medium">
                          Direct Deposit to Chase •••• 4892 ·
                          <span class="text-success font-semibold">Arriving Aug 24</span>
                        </p>
                      </div>
                    </div>
                    <span ui-badge wrap variant="secondary" class="text-xs">Scheduled</span>
                  </div>
                </div>
    
                <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
                  <div class="border-border bg-card rounded-lg border p-3.5 shadow-xs">
                    <span class="text-muted-foreground text-xs font-medium">Completed payouts YTD</span>
                    <div class="text-foreground mt-1 text-xl font-bold tracking-tight tabular-nums">$92,400.00</div>
                    <p class="text-muted-foreground mt-0.5 text-xs">18 completed disbursement cycles</p>
                  </div>
                  <div class="border-border bg-card rounded-lg border p-3.5 shadow-xs">
                    <span class="text-muted-foreground text-xs font-medium">Settlement routing</span>
                    <div class="text-foreground mt-1 text-sm font-semibold">JPMorgan Chase Bank</div>
                    <p class="text-muted-foreground mt-0.5 text-xs tabular-nums">Routing: 021000021 · $0 held</p>
                  </div>
                </div>
    
                <div class="flex items-center justify-between pt-1">
                  <p class="text-muted-foreground text-xs">Payouts release automatically 24h after each guest check-in.</p>
                  <button ui-button variant="outline" size="sm" class="gap-1.5 text-xs">
                    <lucide-icon [img]="Building2" class="size-3.5" />
                    <span>Manage Bank Account</span>
                  </button>
                </div>
              </div>
            </div>
    
            <div ui-card class="flex flex-col justify-between shadow-xs">
              <div ui-card-header>
                <div class="flex items-center justify-between">
                  <div class="space-y-1">
                    <h3 ui-card-title>Dynamic Pricing Suggestions</h3>
                    <p ui-card-description>
                      Machine-learning demand forecasts and local holiday surge pricing recommendations.
                    </p>
                  </div>
                  <span
                    ui-badge
                    wrap
                    variant="outline"
                    class="border-warning/20 bg-warning/10 text-warning gap-1 text-xs font-semibold"
                  >
                    <lucide-icon [img]="TrendingUp" class="size-3" />
                    Smart Rates
                  </span>
                </div>
              </div>
              <div ui-card-content class="space-y-4">
                <div class="border-border/80 bg-muted/30 hover:bg-muted/50 rounded-lg border p-4 transition-colors">
                  <div class="flex items-start gap-3">
                    <div
                      class="border-warning/20 bg-warning/10 text-warning mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs"
                    >
                      <lucide-icon [img]="TrendingUp" class="size-4" />
                    </div>
                    <div class="flex-1 space-y-2">
                      <div class="flex flex-wrap items-center justify-between gap-2">
                        <h4 class="text-foreground text-sm font-semibold">
                          High demand weekend Sep 4-7: increase ADR by +15%
                        </h4>
                        <span ui-badge wrap variant="outline" class="text-xs font-medium">Labor Day Peak</span>
                      </div>
                      <p class="text-muted-foreground text-xs leading-relaxed">
                        Regional guest search volume is up +48% in Malibu and Maui. Raising base rate from $680.00 to
                        $782.00/night captures peak holiday yield.
                      </p>
    
                      <div class="border-border/60 grid grid-cols-1 gap-2 border-t pt-2.5 text-xs sm:grid-cols-3">
                        <div>
                          <span class="text-muted-foreground">Current ADR:</span>
                          <p class="text-foreground font-semibold tabular-nums">$680.00 / night</p>
                        </div>
                        <div>
                          <span class="text-muted-foreground">Suggested ADR:</span>
                          <p class="text-success font-semibold tabular-nums">$782.00 (+15%)</p>
                        </div>
                        <div class="sm:text-right">
                          <span class="text-muted-foreground">Est. Extra Rev:</span>
                          <p class="text-foreground font-semibold tabular-nums">+$408.00 (4 nights)</p>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
    
                @if (isPricingApplied()) {
                  <div
                    class="border-success/20 bg-success/10 flex items-center justify-between rounded-lg border p-3 text-xs"
                  >
                    <div class="text-success flex flex-wrap items-center gap-2 font-medium">
                      <lucide-icon [img]="CheckCircle2" class="size-4 shrink-0" />
                      <span>Suggested +15% rate applied for Sep 4-7 ($782.00/night).</span>
                    </div>
                    <button ui-button variant="ghost" size="sm" class="h-7 text-xs" (click)="isPricingApplied.set(false)">
                      Undo
                    </button>
                  </div>
                } @else {
                  <div class="flex flex-wrap items-center justify-between gap-2 pt-1">
                    <span class="text-muted-foreground text-xs">Algorithm confidence score: 96%</span>
                    <div class="flex flex-wrap items-center gap-2">
                      <button ui-button variant="outline" size="sm" class="text-xs">Customize Rules</button>
                      <button ui-button size="sm" class="gap-1.5 text-xs" (click)="isPricingApplied.set(true)">
                        <lucide-icon [img]="Check" class="size-3.5" />
                        <span>Apply Suggested Rate</span>
                      </button>
                    </div>
                  </div>
                }
              </div>
            </div>
          </div>
    
          <!-- Monthly Revenue Breakdown Table Card -->
          <div ui-card class="shadow-xs">
            <div ui-card-header>
              <div class="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
                <div>
                  <h3 ui-card-title>Monthly Revenue Breakdown</h3>
                  <p ui-card-description>
                    Itemized guest reservations, cleaning fee payouts, platform service commissions, and net disbursements.
                  </p>
                </div>
                <span ui-badge wrap variant="outline" class="w-fit text-xs font-normal tabular-nums">
                  4 reservations · August 2026
                </span>
              </div>
            </div>
            <div ui-card-content class="p-0 sm:p-6 sm:pt-0">
              <div class="overflow-x-auto">
                <table ui-table>
                  <thead ui-table-header>
                    <tr ui-table-row>
                      <th ui-table-head class="min-w-[180px]">Guest & Reservation</th>
                      <th ui-table-head class="min-w-[160px]">Property Booked</th>
                      <th ui-table-head>Dates Booked</th>
                      <th ui-table-head class="text-right">Nightly Rate</th>
                      <th ui-table-head class="text-right">Cleaning Fee</th>
                      <th ui-table-head class="text-right">Host Fee (3%)</th>
                      <th ui-table-head class="text-right">Net Payout</th>
                      <th ui-table-head class="text-right">Status</th>
                    </tr>
                  </thead>
                  <tbody ui-table-body>
                    @for (res of reservations; track res.id) {
                      <tr ui-table-row class="hover:bg-muted/50">
                        <td ui-table-cell>
                          <div class="flex items-center gap-3">
                            <ui-avatar size="sm" class="shrink-0">
                              <ui-avatar-image [src]="res.guest.avatar" [alt]="res.guest.name" />
                              <ui-avatar-fallback class="text-xs font-medium">{{ res.guest.initials }}</ui-avatar-fallback>
                            </ui-avatar>
                            <div class="space-y-0.5">
                              <div class="text-foreground text-sm font-semibold">{{ res.guest.name }}</div>
                              <div class="text-muted-foreground font-mono text-xs tabular-nums">
                                {{ res.confirmationCode }}
                              </div>
                            </div>
                          </div>
                        </td>
    
                        <td ui-table-cell>
                          <div class="space-y-0.5">
                            <div class="text-foreground text-sm font-medium">{{ res.property }}</div>
                            <div class="text-muted-foreground text-xs">{{ res.location }}</div>
                          </div>
                        </td>
    
                        <td ui-table-cell>
                          <div class="text-foreground text-xs font-medium tabular-nums">{{ res.datesBooked }}</div>
                        </td>
    
                        <td ui-table-cell class="text-right">
                          <div class="text-foreground text-xs font-semibold tabular-nums">{{ res.nightlyRate }}</div>
                          <div class="text-muted-foreground text-xs tabular-nums">{{ res.nightsCount }} nights</div>
                        </td>
    
                        <td ui-table-cell class="text-muted-foreground text-right text-xs tabular-nums">
                          {{ res.cleaningFee }}
                        </td>
    
                        <td ui-table-cell class="text-muted-foreground text-right text-xs tabular-nums">
                          {{ res.hostServiceFee }}
                        </td>
    
                        <td ui-table-cell class="text-foreground text-right text-sm font-bold tabular-nums">
                          {{ res.netPayout }}
                        </td>
    
                        <td ui-table-cell class="text-right">
                          <span ui-badge variant="outline" [class]="statusBadgeClass(res)">
                            @if (res.status === 'paid') {
                              <span class="flex items-center gap-1">
                                <lucide-icon [img]="Check" class="size-3" />
                                Paid
                              </span>
                            } @else {
                              <span class="flex items-center gap-1">
                                <lucide-icon [img]="Clock" class="size-3" />
                                Processing
                              </span>
                            }
                          </span>
                        </td>
                      </tr>
                    }
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      `,
    })
    export class UiAirbnbHostEarningsComponent {
      protected readonly Building2 = Building2
      protected readonly Calendar = Calendar
      protected readonly CalendarCheck = CalendarCheck
      protected readonly Check = Check
      protected readonly CheckCircle2 = CheckCircle2
      protected readonly Clock = Clock
      protected readonly DollarSign = DollarSign
      protected readonly Download = Download
      protected readonly Home = Home
      protected readonly Landmark = Landmark
      protected readonly TrendingUp = TrendingUp
    
      protected readonly reservations = reservations
    
      @Input() set initialProperty(v: string | undefined) {
        this.selectedProperty.set(v ?? 'all')
      }
      @Input() set initialTimeframe(v: string | undefined) {
        this.selectedTimeframe.set(v ?? 'this-month')
      }
      @Input('class') className?: string
    
      readonly selectedProperty = signal('all')
      readonly selectedTimeframe = signal('this-month')
      readonly isPricingApplied = signal(false)
    
      get rootClass(): string {
        return cn('mx-auto w-full max-w-6xl space-y-6', this.className)
      }
    
      statusBadgeClass(res: ReservationPayout): string {
        return cn(
          'text-xs font-semibold tabular-nums',
          res.status === 'paid' && 'border-success/20 bg-success/10 text-success',
          res.status === 'processing' && 'border-info/20 bg-info/10 text-info',
        )
      }
    }
    
  • src/app/components/blocks/airbnb-host-earnings/index.ts0.2 kB

Raw manifest:https://uipkge.dev/r/angular/airbnb-host-earnings.json