From f1ee0be61669f8856f49d50aaa27752727715b05 Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Thu, 2 Jul 2026 22:54:39 +0300
Subject: [PATCH 01/13] docs(billing): GCP cloud billing design spec (BigQuery
export)
Co-Authored-By: Claude Opus 4.8
---
.../2026-07-02-gcp-cloud-billing-design.md | 190 ++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 docs/superpowers/specs/2026-07-02-gcp-cloud-billing-design.md
diff --git a/docs/superpowers/specs/2026-07-02-gcp-cloud-billing-design.md b/docs/superpowers/specs/2026-07-02-gcp-cloud-billing-design.md
new file mode 100644
index 00000000..bafd2d01
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-02-gcp-cloud-billing-design.md
@@ -0,0 +1,190 @@
+# GCP Cloud Billing (BigQuery billing export) — Design Spec
+
+**Date:** 2026-07-02
+**Status:** Approved for planning
+**Author:** Patrick Walukagga (with Claude Code)
+
+## Summary
+
+Add **GCP** cost/usage billing as a second provider under the existing **Cloud** category on the
+admin billing dashboard (`/admin/billing`), alongside **AWS**. GCP has no on-demand cost API
+(the Cloud Billing API only exposes account info, budgets, and the pricing catalog — not actual
+consumed spend), so detailed cost/usage comes from **Cloud Billing export to BigQuery**: the
+standard usage-cost export table (`gcp_billing_export_v1_*`), queried with parameterized SQL via
+`google-cloud-bigquery`, broken down by **service** and **SKU**, viewable hourly / daily / monthly
+/ yearly and over custom date ranges, with a cost-over-time graph and a searchable cost-and-usage
+breakdown table.
+
+GCP slots into the category abstraction and provider-agnostic pipeline built for Vast.ai and AWS:
+it is a new provider mapped to the existing `cloud` category; the schema / aggregation / caching /
+router layers are reused unchanged.
+
+## Decisions (locked)
+
+| Decision | Choice |
+|---|---|
+| Data source | **Standard BigQuery billing export** (`gcp_billing_export_v1_*`), queried via `google-cloud-bigquery` |
+| Cost basis | **Net cost** = `cost` + sum of `credits.amount` (what is actually billed after credits/discounts) — the GCP analogue of AWS `UnblendedCost` |
+| Breakdown depth | **Service + SKU** (`service.description` + `sku.description`) — parity with the AWS Service + Usage-type table |
+| Credentials/config | **Env var `GCP_BILLING_BQ_TABLE`** (fully-qualified `project.dataset.table`) + existing `google.auth.default()` ADC (already used by `storage_service`) |
+| Cloud tab composition | **AWS + GCP combined** (like Inference combines Runpod + Modal), with the provider filter extended to **All / AWS / GCP** |
+| Resource-level / detailed export | **Deferred** (`gcp_billing_export_resource_v1_*`); SKU is the MVP sub-line dimension |
+
+## Scope
+
+### In this spec
+- `PROVIDER_CATEGORY["gcp"] = "cloud"` (category tuple unchanged — `cloud` already exists).
+- `GcpAnalyticsProvider`: parameterized BigQuery query against the export table, grouped by
+ time-bucket + SERVICE + SKU, net cost incl. credits, normalized into per-(service, sku, bucket)
+ `BillingRecord`s.
+- Generalize the `active_services` summary metric to count distinct services across **all** cloud
+ providers (aws + gcp), not aws-only. (`usage_type` group key already exists and is reused.)
+- Frontend: Cloud tab combines AWS + GCP; extend the provider filter to All / AWS / GCP; reuse the
+ cost-over-time chart, searchable Service↔Usage-type breakdown table, and summary cards; add a GCP
+ explainer paragraph. Tab label `Cloud`.
+- Config (`gcp_billing_bq_table`, `gcp_billing_project_id`) + `google-cloud-bigquery` dependency.
+ Tests + docs.
+
+### Deferred (later)
+- Detailed/resource-level export (`gcp_billing_export_resource_v1_*`, RESOURCE-level rows).
+- Heroku provider (also `cloud` category) — separate spec.
+- Additional group dimensions (PROJECT, REGION/location, labels) as selectable breakdowns.
+
+## Architecture
+
+### Category & backend layout
+- `app/integrations/billing/categories.py`: `PROVIDER_CATEGORY["gcp"] = "cloud"`. `CATEGORIES`
+ unchanged (`("inference", "training", "cloud")`). `providers_in_category("cloud")` →
+ `["aws", "gcp"]`. The router already validates `category`, so no router change beyond the map
+ growing.
+- `app/integrations/billing/gcp.py`: `GcpAnalyticsProvider(AnalyticsProvider)`, `name="gcp"`.
+- `app/services/billing_analytics/service.py`: register `self.gcp = GcpAnalyticsProvider()` and add
+ `"gcp": self.gcp` to `_provider_by_name`; `_providers_for` already routes by category via
+ `providers_in_category`.
+- `app/services/billing_analytics/aggregation.py`: `summarize` computes `active_services` as the
+ count of distinct `object_id`s across all providers in the `cloud` category (aws + gcp). The
+ `usage_type` group key (`lambda r: r.metadata.get("usage_type")`) is reused — GCP stores SKU
+ there. `provider_totals` already appends arbitrary providers dynamically, so the GCP pie slice
+ needs no change.
+- `app/schemas/billing_analytics.py`: `Provider` Literal += `"gcp"`. `SummaryResponse.active_services`
+ already exists.
+
+### GCP provider
+- **Client:** `_client()` lazily does `from google.cloud import bigquery; return
+ bigquery.Client(project=)`. Imported lazily so import
+ time never requires BigQuery config; this method is the test seam (patched in tests). Credentials
+ via ADC (`google.auth.default()` — env `GOOGLE_APPLICATION_CREDENTIALS` or Cloud Run workload
+ identity), consistent with `storage_service`.
+- **Async:** `google-cloud-bigquery` is synchronous → the query runs in `asyncio.to_thread`
+ (mirrors the AWS and Modal providers).
+- **`is_available()`** = `bool(settings.gcp_billing_bq_table)`. Fail closed to `ProviderUnavailable`
+ otherwise.
+- **Query** (parameterized; `base_resolution == "hour"` → `HOUR` truncation, else `DAY`):
+ ```sql
+ SELECT
+ TIMESTAMP_TRUNC(usage_start_time, {HOUR|DAY}) AS bucket,
+ service.description AS service,
+ sku.description AS sku,
+ SUM(cost + IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS net_cost,
+ ANY_VALUE(usage.unit) AS unit,
+ ANY_VALUE(currency) AS currency
+ FROM ``
+ WHERE usage_start_time >= @start AND usage_start_time < @end
+ GROUP BY bucket, service, sku
+ HAVING net_cost != 0
+ ORDER BY bucket
+ ```
+ - `@start` / `@end` passed as `bigquery.ScalarQueryParameter("start"/"end", "TIMESTAMP", ...)`;
+ `End` exclusive. The granularity token (`HOUR`/`DAY`) is a fixed internal literal, never user
+ input.
+ - **Table name** cannot be parameterized in BigQuery (identifiers are not parameterizable). It
+ comes only from trusted config (`settings.gcp_billing_bq_table`), is format-validated against
+ `^[A-Za-z0-9_-]+\.[A-Za-z0-9_]+\.[A-Za-z0-9_]+$` (raise `ProviderUnavailable` on mismatch), and
+ is backtick-quoted. Zero user-controlled input reaches the SQL string.
+ - Week/month/year resolutions are served by fetching `DAY` and letting the aggregation layer roll
+ up (consistent with the other providers). GCP has **no** 14-day hourly limit (that constraint
+ was AWS-specific).
+- **Normalize** each result row:
+ - `BillingRecord(provider="gcp", object_id=service, object_name=service, timestamp=, cost=net_cost, runtime_ms=None, storage_gb=None, metadata={"kind":"gcp_service",
+ "usage_type":sku, "unit":unit, "currency":currency})`.
+ - `bucket` (a `datetime` with tzinfo=UTC from BigQuery) is coerced to naive UTC by the existing
+ `BillingRecord.timestamp` field validator.
+ - Rows with `net_cost == 0` are already excluded by the SQL `HAVING`; the normalizer additionally
+ guards against `None`/blank service or sku.
+
+### GCP constraints (handled)
+- **BigQuery is billed by bytes scanned** (on-demand ~$6.25/TB, first 1 TB/month free). The export
+ table is small (tens of MB to a few GB) and the existing cache + request-coalescing +
+ `now`-quantization minimize queries. No new mechanism needed; documented.
+- **Export latency:** billing-export data can lag up to ~a day, so the current partial day may be
+ incomplete. Noted in the explainer; no special handling.
+- All `google.cloud.exceptions` / BigQuery / auth errors → `ProviderUnavailable("gcp", ...)` (never
+ leak); credentials never appear in messages/warnings/logs.
+- If `gcp_billing_bq_table` is unset, GCP is unavailable and the Cloud tab still shows AWS — the
+ service already tolerates per-provider failure via `asyncio.gather(return_exceptions=True)` and
+ surfaces a `warnings[]` entry.
+
+## Frontend (Cloud tab: AWS + GCP)
+
+- The Cloud tab (`category="cloud"`) now aggregates AWS + GCP. Reuse the existing cards, cost-over-
+ time chart, breakdown table, and explainer.
+- **Provider filter:** extend the provider dropdown to render for the `cloud` category with options
+ **All / AWS / GCP** (category-gated; inference still shows Runpod/Modal). Selecting one sets
+ `provider` in the filters, which the backend routes within the category.
+- **Cost-and-usage graph:** timeseries requested with `group_by=object` (service) → one line per
+ service plus the dashed Total (existing multi-line cost chart), across whichever providers the
+ filter selects.
+- **Searchable breakdown table:** fed by `/breakdown` with the existing group toggle — Service
+ (`group_by=object`) ↔ Usage-type/SKU (`group_by=usage_type`) — plus client-side search. Columns:
+ Service / Usage-type, Cost, share %. For GCP rows the Usage-type value is the SKU (stored in
+ `metadata.usage_type`), so the toggle works unchanged.
+- **Summary cards** (category-aware): Total Spend, Avg Daily Spend, Active Services
+ (`active_services`, now spanning aws + gcp), Top Service. Inference/training cards unchanged.
+- **Explainer:** add a GCP paragraph (Cloud Billing export to BigQuery; net cost including credits;
+ breakdown by service & SKU; data freshness bounded by export latency, so today may be partial;
+ each query scans BigQuery so figures are cached briefly).
+- `useBillingAnalytics`: provider union gains `"gcp"`; `BillingFilters.category` already includes
+ `"cloud"`. The cloud provider dropdown options are `all | aws | gcp`.
+
+## Schema / config / caching / testing
+
+- **Schema:** `Provider` Literal += `"gcp"`. `SummaryResponse.active_services` already present
+ (semantics broadened to all cloud providers).
+- **Config (`config.py`):** `gcp_billing_bq_table: Optional[str]` (default `None`; fully-qualified
+ `project.dataset.table`); `gcp_billing_project_id: Optional[str]` (default `None`; BigQuery job/
+ billing project, falls back to `settings.gcp_project_id`). GCP credentials are read by ADC from
+ the environment (not stored in settings). Add `google-cloud-bigquery` to `requirements.txt`
+ (recent pin, confirmed with the user during planning).
+- **Caching:** cache key already includes `category` and `provider`
+ (`billing:v3:{category}:{provider}:...`); no change.
+- **Testing:** `test_gcp_billing.py` (mocked `bigquery.Client` / query-job row iterator: service+SKU
+ normalization, net-cost incl. credits, zero/empty filtering, HOUR vs DAY truncation selection,
+ missing/invalid table → `ProviderUnavailable`, generic exception → `ProviderUnavailable`,
+ `is_available` with/without table). Service test: `category="cloud"` → both aws and gcp queried.
+ Aggregation test: `active_services` counts distinct services across aws + gcp; `usage_type` group
+ key returns SKU for gcp records. Router test: `category=cloud` unaffected. Frontend build
+ (`tsc && vite build`). Follows `asyncio_mode=auto`; reuses existing fixtures. Lint gate: changed
+ files clean under black/isort/flake8 (repo `make lint-check` / `npm run lint` are pre-existingly
+ broken).
+
+## Risks
+
+- **BigQuery scan cost** — mitigated by the existing cache/coalescing/quantization and the 1 TB/month
+ free tier; a misconfigured short cache TTL or long hourly ranges would raise scan volume (note in
+ docs).
+- **Export latency / partial today** — billing export lags up to ~a day; surfaced in the explainer.
+- **`google-cloud-bigquery` version pin** — recent version proposed at implementation and confirmed
+ with the user (as with boto3); code defensively against response-shape assumptions.
+- **Billing-export schema variance** — the standard `v1` export schema is stable
+ (`service.description`, `sku.description`, `usage_start_time`, `cost`, `credits[]`, `currency`,
+ `usage.unit`); verified against live `google-cloud-bigquery` docs at implementation.
+
+## Future extensibility
+
+- **Heroku** = another `cloud`-category provider: add the provider + a `PROVIDER_CATEGORY` entry;
+ the tab, schema, aggregation, and UI are unchanged.
+- **Detailed/resource-level** GCP breakdown = a later enhancement querying
+ `gcp_billing_export_resource_v1_*` behind the same provider interface.
+- **Extra dimensions** (project, region, labels) = additional selectable `group_by` values reusing
+ the existing group-key mechanism.
From 760a87af6f84cc003e2760ecb2267cf5b36979ce Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Fri, 3 Jul 2026 07:20:03 +0300
Subject: [PATCH 02/13] feat(billing): scaffold GCP cloud provider (category,
schema, config, dep)
Co-Authored-By: Claude Opus 4.8
---
app/core/config.py | 16 ++++++++++++++++
app/integrations/billing/categories.py | 1 +
app/schemas/billing_analytics.py | 2 +-
.../test_integrations/test_billing_categories.py | 11 +++++++++++
requirements.txt | 1 +
5 files changed, 30 insertions(+), 1 deletion(-)
create mode 100644 app/tests/test_integrations/test_billing_categories.py
diff --git a/app/core/config.py b/app/core/config.py
index 6bf7f843..9dfbf579 100644
--- a/app/core/config.py
+++ b/app/core/config.py
@@ -181,6 +181,22 @@ def vast_contract_types(self) -> list[str]:
description="Cost Explorer metric to report (e.g. UnblendedCost, AmortizedCost).",
)
+ # GCP (cloud) billing — BigQuery billing export
+ gcp_billing_bq_table: Optional[str] = Field(
+ default=None,
+ description=(
+ "Fully-qualified BigQuery billing-export table "
+ "(project.dataset.table), e.g. my-proj.billing.gcp_billing_export_v1_XXXX."
+ ),
+ )
+ gcp_billing_project_id: Optional[str] = Field(
+ default=None,
+ description=(
+ "GCP project to run the BigQuery job in (billed for the query). "
+ "Falls back to gcp_project_id when unset."
+ ),
+ )
+
billing_cache_ttl_seconds: int = Field(
default=3600, description="TTL for cached normalized billing records."
)
diff --git a/app/integrations/billing/categories.py b/app/integrations/billing/categories.py
index d61f2a9e..a3c4fbc0 100644
--- a/app/integrations/billing/categories.py
+++ b/app/integrations/billing/categories.py
@@ -12,6 +12,7 @@
"modal": "inference",
"vastai": "training",
"aws": "cloud",
+ "gcp": "cloud",
}
CATEGORIES: tuple[str, ...] = ("inference", "training", "cloud")
diff --git a/app/schemas/billing_analytics.py b/app/schemas/billing_analytics.py
index 240e3920..e0f447f8 100644
--- a/app/schemas/billing_analytics.py
+++ b/app/schemas/billing_analytics.py
@@ -11,7 +11,7 @@
from pydantic import BaseModel, ConfigDict, Field, field_validator
-Provider = Literal["runpod", "modal", "vastai", "aws"]
+Provider = Literal["runpod", "modal", "vastai", "aws", "gcp"]
class BillingRecord(BaseModel):
diff --git a/app/tests/test_integrations/test_billing_categories.py b/app/tests/test_integrations/test_billing_categories.py
new file mode 100644
index 00000000..6676eb63
--- /dev/null
+++ b/app/tests/test_integrations/test_billing_categories.py
@@ -0,0 +1,11 @@
+"""Tests for billing provider category mapping."""
+
+
+def test_gcp_is_in_cloud_category():
+ from app.integrations.billing.categories import (
+ PROVIDER_CATEGORY,
+ providers_in_category,
+ )
+
+ assert PROVIDER_CATEGORY["gcp"] == "cloud"
+ assert providers_in_category("cloud") == ["aws", "gcp"]
diff --git a/requirements.txt b/requirements.txt
index e56a6276..1afabdf4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,6 +9,7 @@ firebase-admin==6.5.0
# Google Cloud packages
google-analytics-data>=0.18.0
google-cloud-storage==2.18.2
+google-cloud-bigquery==3.42.1
# HTTP client for async requests
httpx==0.28.1
newrelic
From 7b0a3800bb360b679f04da7dd80bcc63166b0bfd Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Fri, 3 Jul 2026 07:29:10 +0300
Subject: [PATCH 03/13] feat(billing): add GCP provider querying BigQuery
billing export
---
app/integrations/billing/gcp.py | 121 +++++++++++++
.../test_integrations/test_gcp_billing.py | 160 ++++++++++++++++++
2 files changed, 281 insertions(+)
create mode 100644 app/integrations/billing/gcp.py
create mode 100644 app/tests/test_integrations/test_gcp_billing.py
diff --git a/app/integrations/billing/gcp.py b/app/integrations/billing/gcp.py
new file mode 100644
index 00000000..c7f9540c
--- /dev/null
+++ b/app/integrations/billing/gcp.py
@@ -0,0 +1,121 @@
+"""GCP billing analytics provider (Cloud Billing export in BigQuery)."""
+
+from __future__ import annotations
+
+import asyncio
+import logging
+import re
+
+from app.core.config import settings
+from app.integrations.billing.base import (
+ AnalyticsProvider,
+ ProviderQuery,
+ ProviderUnavailable,
+)
+from app.schemas.billing_analytics import BillingRecord
+
+logger = logging.getLogger(__name__)
+
+# project.dataset.table — trusted config only, validated before it reaches SQL.
+_TABLE_RE = re.compile(r"^[A-Za-z0-9_-]+\.[A-Za-z0-9_]+\.[A-Za-z0-9_]+$")
+
+
+class GcpAnalyticsProvider(AnalyticsProvider):
+ name = "gcp"
+
+ def __init__(self) -> None:
+ self.table = settings.gcp_billing_bq_table
+ self.project = settings.gcp_billing_project_id or settings.gcp_project_id
+
+ async def is_available(self) -> bool:
+ return bool(self.table)
+
+ def _client(self):
+ """Construct the BigQuery client. Patched in tests."""
+ from google.cloud import bigquery # lazy: import-time never needs BigQuery
+
+ return bigquery.Client(project=self.project)
+
+ def _granularity(self, base_resolution: str) -> str:
+ return "HOUR" if base_resolution == "hour" else "DAY"
+
+ def _build_sql(self, granularity: str) -> str:
+ # self.table is validated by the caller and backtick-quoted; @start/@end
+ # are bound parameters; granularity is a fixed internal literal.
+ return f"""
+ SELECT
+ TIMESTAMP_TRUNC(usage_start_time, {granularity}) AS bucket,
+ service.description AS service,
+ sku.description AS sku,
+ SUM(cost + IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS net_cost,
+ ANY_VALUE(usage.unit) AS unit,
+ ANY_VALUE(currency) AS currency
+ FROM `{self.table}`
+ WHERE usage_start_time >= @start AND usage_start_time < @end
+ GROUP BY bucket, service, sku
+ HAVING net_cost != 0
+ ORDER BY bucket
+ """
+
+ def _run_query(self, query: ProviderQuery) -> list:
+ """Blocking BigQuery call. Runs in a worker thread."""
+ from google.cloud import bigquery
+
+ granularity = self._granularity(query.base_resolution)
+ sql = self._build_sql(granularity)
+ job_config = bigquery.QueryJobConfig(
+ query_parameters=[
+ bigquery.ScalarQueryParameter("start", "TIMESTAMP", query.start),
+ bigquery.ScalarQueryParameter("end", "TIMESTAMP", query.end),
+ ]
+ )
+ client = self._client()
+ return list(client.query(sql, job_config=job_config).result())
+
+ def _normalize(self, rows: list) -> list[BillingRecord]:
+ records: list[BillingRecord] = []
+ for row in rows:
+ service = row["service"]
+ if not service:
+ continue
+ cost = float(row["net_cost"] or 0.0)
+ if cost == 0.0:
+ continue
+ records.append(
+ BillingRecord(
+ provider="gcp",
+ object_id=str(service),
+ object_name=str(service),
+ timestamp=row["bucket"],
+ cost=cost,
+ runtime_ms=None,
+ storage_gb=None,
+ metadata={
+ "kind": "gcp_service",
+ "usage_type": row["sku"],
+ "unit": row["unit"],
+ "currency": row["currency"],
+ },
+ )
+ )
+ return records
+
+ async def fetch_records(self, query: ProviderQuery) -> list[BillingRecord]:
+ if not self.table:
+ raise ProviderUnavailable(
+ "gcp", "GCP billing export table is not configured"
+ )
+ if not _TABLE_RE.match(self.table):
+ raise ProviderUnavailable(
+ "gcp",
+ "GCP billing export table must be a fully-qualified "
+ "project.dataset.table identifier",
+ )
+ try:
+ rows = await asyncio.to_thread(self._run_query, query)
+ return self._normalize(rows)
+ except ProviderUnavailable:
+ raise
+ except Exception as exc: # BigQuery / auth errors — never leak details
+ logger.exception("gcp_billing_query_failed")
+ raise ProviderUnavailable("gcp", "BigQuery billing query failed") from exc
diff --git a/app/tests/test_integrations/test_gcp_billing.py b/app/tests/test_integrations/test_gcp_billing.py
new file mode 100644
index 00000000..8e0421d3
--- /dev/null
+++ b/app/tests/test_integrations/test_gcp_billing.py
@@ -0,0 +1,160 @@
+from datetime import datetime, timezone
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from app.integrations.billing.base import ProviderQuery, ProviderUnavailable
+from app.integrations.billing.gcp import GcpAnalyticsProvider
+
+
+def _query(res="day", start=datetime(2026, 6, 1), end=datetime(2026, 6, 3)):
+ return ProviderQuery(start=start, end=end, base_resolution=res)
+
+
+def _rows():
+ # Rows are dict-like; bigquery.Row supports the same subscript access.
+ return [
+ {
+ "bucket": datetime(2026, 6, 1, tzinfo=timezone.utc),
+ "service": "Compute Engine",
+ "sku": "N1 Predefined Instance Core running in Americas",
+ "net_cost": 12.5,
+ "unit": "seconds",
+ "currency": "USD",
+ },
+ {
+ "bucket": datetime(2026, 6, 2, tzinfo=timezone.utc),
+ "service": "Cloud Storage",
+ "sku": "Standard Storage US",
+ "net_cost": 3.0,
+ "unit": "byte-seconds",
+ "currency": "USD",
+ },
+ ]
+
+
+def _provider_with_table(
+ monkeypatch, table="my-proj.billing.gcp_billing_export_v1_ABC123"
+):
+ monkeypatch.setattr(
+ "app.integrations.billing.gcp.settings.gcp_billing_bq_table",
+ table,
+ raising=False,
+ )
+ return GcpAnalyticsProvider()
+
+
+async def test_fetch_records_normalizes_service_and_sku(monkeypatch):
+ provider = _provider_with_table(monkeypatch)
+ fake_client = MagicMock()
+ fake_job = MagicMock()
+ fake_job.result.return_value = _rows()
+ fake_client.query.return_value = fake_job
+ with patch.object(provider, "_client", return_value=fake_client):
+ records = await provider.fetch_records(_query())
+
+ assert fake_client.query.call_count == 1
+ assert {r.object_name for r in records} == {"Compute Engine", "Cloud Storage"}
+ r0 = records[0]
+ assert r0.provider == "gcp"
+ assert r0.cost == 12.5
+ assert r0.metadata["kind"] == "gcp_service"
+ assert (
+ r0.metadata["usage_type"] == "N1 Predefined Instance Core running in Americas"
+ )
+ assert r0.metadata["currency"] == "USD"
+ # tz-aware bucket is coerced to naive UTC by BillingRecord's validator
+ assert r0.timestamp == datetime(2026, 6, 1)
+
+
+async def test_hourly_resolution_selects_hour_truncation(monkeypatch):
+ provider = _provider_with_table(monkeypatch)
+ fake_client = MagicMock()
+ fake_job = MagicMock()
+ fake_job.result.return_value = []
+ fake_client.query.return_value = fake_job
+ with patch.object(provider, "_client", return_value=fake_client):
+ await provider.fetch_records(_query(res="hour"))
+ sql = fake_client.query.call_args.args[0]
+ assert "TIMESTAMP_TRUNC(usage_start_time, HOUR)" in sql
+
+
+async def test_daily_resolution_selects_day_truncation(monkeypatch):
+ provider = _provider_with_table(monkeypatch)
+ fake_client = MagicMock()
+ fake_job = MagicMock()
+ fake_job.result.return_value = []
+ fake_client.query.return_value = fake_job
+ with patch.object(provider, "_client", return_value=fake_client):
+ await provider.fetch_records(_query(res="day"))
+ sql = fake_client.query.call_args.args[0]
+ assert "TIMESTAMP_TRUNC(usage_start_time, DAY)" in sql
+ # table is backtick-quoted, never string-interpolated dates
+ assert "`my-proj.billing.gcp_billing_export_v1_ABC123`" in sql
+
+
+async def test_missing_table_is_unavailable(monkeypatch):
+ monkeypatch.setattr(
+ "app.integrations.billing.gcp.settings.gcp_billing_bq_table",
+ None,
+ raising=False,
+ )
+ provider = GcpAnalyticsProvider()
+ assert await provider.is_available() is False
+ with pytest.raises(ProviderUnavailable):
+ await provider.fetch_records(_query())
+
+
+async def test_invalid_table_name_is_unavailable(monkeypatch):
+ provider = _provider_with_table(monkeypatch, table="not-a-valid-table")
+ with pytest.raises(ProviderUnavailable):
+ await provider.fetch_records(_query())
+
+
+async def test_query_errors_are_wrapped(monkeypatch):
+ provider = _provider_with_table(monkeypatch)
+ fake_client = MagicMock()
+ fake_client.query.side_effect = RuntimeError("PermissionDenied on dataset")
+ with patch.object(provider, "_client", return_value=fake_client):
+ with pytest.raises(ProviderUnavailable) as exc:
+ await provider.fetch_records(_query())
+ # credentials/detail must not leak verbatim into the surfaced message
+ assert "PermissionDenied on dataset" not in exc.value.message
+
+
+async def test_zero_and_blank_rows_are_skipped(monkeypatch):
+ provider = _provider_with_table(monkeypatch)
+ rows = [
+ {
+ "bucket": datetime(2026, 6, 1, tzinfo=timezone.utc),
+ "service": None,
+ "sku": "x",
+ "net_cost": 5.0,
+ "unit": "u",
+ "currency": "USD",
+ },
+ {
+ "bucket": datetime(2026, 6, 1, tzinfo=timezone.utc),
+ "service": "Compute Engine",
+ "sku": "core",
+ "net_cost": 0.0,
+ "unit": "u",
+ "currency": "USD",
+ },
+ {
+ "bucket": datetime(2026, 6, 1, tzinfo=timezone.utc),
+ "service": "Compute Engine",
+ "sku": "core",
+ "net_cost": 7.0,
+ "unit": "u",
+ "currency": "USD",
+ },
+ ]
+ fake_client = MagicMock()
+ fake_job = MagicMock()
+ fake_job.result.return_value = rows
+ fake_client.query.return_value = fake_job
+ with patch.object(provider, "_client", return_value=fake_client):
+ records = await provider.fetch_records(_query())
+ assert len(records) == 1
+ assert records[0].cost == 7.0
From 18fd23323a8465a08e1d37229c97985013296a54 Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Fri, 3 Jul 2026 07:35:48 +0300
Subject: [PATCH 04/13] feat(billing): register GCP provider and count it in
active_services
---
app/services/billing_analytics/aggregation.py | 2 +-
app/services/billing_analytics/service.py | 5 ++++-
app/tests/test_billing_aggregation.py | 21 +++++++++++++++++++
.../test_billing_analytics_service.py | 10 +++++++++
4 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/app/services/billing_analytics/aggregation.py b/app/services/billing_analytics/aggregation.py
index 1d552663..365f4d53 100644
--- a/app/services/billing_analytics/aggregation.py
+++ b/app/services/billing_analytics/aggregation.py
@@ -129,7 +129,7 @@ def summarize(records: list[BillingRecord], num_days: int) -> dict:
endpoints = {r.object_id for r in runpod_endpoint_records}
apps = {r.object_id for r in records if r.provider == "modal"}
instances = {r.object_id for r in records if r.provider == "vastai"}
- services = {r.object_id for r in records if r.provider == "aws"}
+ services = {r.object_id for r in records if r.provider in ("aws", "gcp")}
endpoint_rows = group_records(runpod_endpoint_records, "endpoint")
highest_endpoint = (
diff --git a/app/services/billing_analytics/service.py b/app/services/billing_analytics/service.py
index d2a612da..81dbbd44 100644
--- a/app/services/billing_analytics/service.py
+++ b/app/services/billing_analytics/service.py
@@ -16,6 +16,7 @@
ProviderUnavailable,
)
from app.integrations.billing.categories import providers_in_category
+from app.integrations.billing.gcp import GcpAnalyticsProvider
from app.integrations.billing.modal import ModalAnalyticsProvider
from app.integrations.billing.runpod import RunpodAnalyticsProvider
from app.integrations.billing.vastai import VastaiAnalyticsProvider
@@ -37,7 +38,7 @@
@dataclass
class BillingQueryParams:
- provider: str # "all" | "runpod" | "modal" | "vastai"
+ provider: str # "all" | "runpod" | "modal" | "vastai" | "aws" | "gcp"
start: datetime
end: datetime
resolution: str # display: hour | day | week | month | year
@@ -67,6 +68,7 @@ def __init__(
self.modal = modal_provider or ModalAnalyticsProvider()
self.vastai = VastaiAnalyticsProvider()
self.aws = AwsAnalyticsProvider()
+ self.gcp = GcpAnalyticsProvider()
self.cache = cache or get_cache_backend()
self.ttl = settings.billing_cache_ttl_seconds
# Runpod endpoint IDs to scope billing to (empty = all account endpoints).
@@ -93,6 +95,7 @@ def _provider_by_name(self, name: str) -> AnalyticsProvider:
"modal": self.modal,
"vastai": self.vastai,
"aws": self.aws,
+ "gcp": self.gcp,
}[name]
def _providers_for(self, category: str, provider: str) -> list[AnalyticsProvider]:
diff --git a/app/tests/test_billing_aggregation.py b/app/tests/test_billing_aggregation.py
index 5890a9ff..b76b3e7a 100644
--- a/app/tests/test_billing_aggregation.py
+++ b/app/tests/test_billing_aggregation.py
@@ -381,3 +381,24 @@ def test_summarize_active_services():
s = summarize(recs, num_days=1)
assert s["active_services"] == 2
assert s["active_endpoints"] == 1
+
+
+def test_active_services_counts_aws_and_gcp():
+ from datetime import datetime
+
+ from app.schemas.billing_analytics import BillingRecord
+ from app.services.billing_analytics import aggregation
+
+ records = [
+ BillingRecord(provider="aws", object_id="Amazon EC2", object_name="Amazon EC2",
+ timestamp=datetime(2026, 6, 1), cost=1.0,
+ metadata={"kind": "aws_service", "usage_type": "BoxUsage"}),
+ BillingRecord(provider="gcp", object_id="Compute Engine", object_name="Compute Engine",
+ timestamp=datetime(2026, 6, 1), cost=2.0,
+ metadata={"kind": "gcp_service", "usage_type": "core"}),
+ BillingRecord(provider="gcp", object_id="Cloud Storage", object_name="Cloud Storage",
+ timestamp=datetime(2026, 6, 1), cost=3.0,
+ metadata={"kind": "gcp_service", "usage_type": "std"}),
+ ]
+ out = aggregation.summarize(records, num_days=1)
+ assert out["active_services"] == 3 # EC2 + Compute Engine + Cloud Storage
diff --git a/app/tests/test_services/test_billing_analytics_service.py b/app/tests/test_services/test_billing_analytics_service.py
index 5fe9382d..236f3500 100644
--- a/app/tests/test_services/test_billing_analytics_service.py
+++ b/app/tests/test_services/test_billing_analytics_service.py
@@ -276,3 +276,13 @@ async def test_cloud_category_uses_only_aws():
modal.fetch_records.assert_not_awaited()
assert result.total_spend == 9.0
assert result.active_services == 1
+
+
+def test_cloud_category_routes_to_aws_and_gcp():
+ from app.services.billing_analytics.service import BillingAnalyticsService
+
+ svc = BillingAnalyticsService()
+ providers = svc._providers_for("cloud", "all")
+ names = {p.name for p in providers}
+ assert names == {"aws", "gcp"}
+ assert svc._provider_by_name("gcp").name == "gcp"
From d1477f4af8f4f2584820c9521d5bd2f7d0fcc422 Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Fri, 3 Jul 2026 07:40:30 +0300
Subject: [PATCH 05/13] test(billing): harden cloud-category test for aws+gcp
(mock gcp)
Co-Authored-By: Claude Sonnet 4.6
---
.../test_billing_analytics_service.py | 27 +++++++++++++++----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/app/tests/test_services/test_billing_analytics_service.py b/app/tests/test_services/test_billing_analytics_service.py
index 236f3500..ec3eef6c 100644
--- a/app/tests/test_services/test_billing_analytics_service.py
+++ b/app/tests/test_services/test_billing_analytics_service.py
@@ -254,15 +254,30 @@ def _service_with_aws():
)
]
)
+ gcp = AsyncMock()
+ gcp.name = "gcp"
+ gcp.fetch_records = AsyncMock(
+ return_value=[
+ BillingRecord(
+ provider="gcp",
+ object_id="Compute Engine",
+ object_name="Compute Engine",
+ timestamp=datetime(2026, 6, 1),
+ cost=4.0,
+ metadata={"usage_type": "N1 Predefined Core"},
+ )
+ ]
+ )
service = BillingAnalyticsService(
runpod_provider=runpod, modal_provider=modal, cache=FakeCache()
)
service.aws = aws
- return service, runpod, modal, aws
+ service.gcp = gcp
+ return service, runpod, modal, aws, gcp
-async def test_cloud_category_uses_only_aws():
- service, runpod, modal, aws = _service_with_aws()
+async def test_cloud_category_uses_aws_and_gcp():
+ service, runpod, modal, aws, gcp = _service_with_aws()
p = BillingQueryParams(
provider="all",
start=datetime(2026, 6, 1),
@@ -272,10 +287,12 @@ async def test_cloud_category_uses_only_aws():
)
result = await service.summary(p)
aws.fetch_records.assert_awaited()
+ gcp.fetch_records.assert_awaited()
runpod.fetch_records.assert_not_awaited()
modal.fetch_records.assert_not_awaited()
- assert result.total_spend == 9.0
- assert result.active_services == 1
+ assert result.total_spend == 13.0
+ assert result.active_services == 2
+ assert result.warnings == []
def test_cloud_category_routes_to_aws_and_gcp():
From 71bf250bfabc212564d921a554f445e61a5ccbb0 Mon Sep 17 00:00:00 2001
From: Patrick Walukagga
Date: Fri, 3 Jul 2026 07:46:05 +0300
Subject: [PATCH 06/13] feat(billing): Cloud tab combines AWS + GCP with
provider filter; docs
Co-Authored-By: Claude Opus 4.8
---
.../{index-Sk8NKe7P.js => index-DRXGNIcd.js} | 2 +-
app/static/react_build/index.html | 2 +-
docs/billing-analytics.md | 28 +++++++++++++++----
frontend/src/hooks/useBillingAnalytics.ts | 2 +-
frontend/src/pages/AdminBilling.tsx | 26 +++++++++++++----
5 files changed, 47 insertions(+), 13 deletions(-)
rename app/static/react_build/assets/{index-Sk8NKe7P.js => index-DRXGNIcd.js} (89%)
diff --git a/app/static/react_build/assets/index-Sk8NKe7P.js b/app/static/react_build/assets/index-DRXGNIcd.js
similarity index 89%
rename from app/static/react_build/assets/index-Sk8NKe7P.js
rename to app/static/react_build/assets/index-DRXGNIcd.js
index 4d1786d8..66cef344 100644
--- a/app/static/react_build/assets/index-Sk8NKe7P.js
+++ b/app/static/react_build/assets/index-DRXGNIcd.js
@@ -430,7 +430,7 @@ Error generating stack: `+o.message+`
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
- */function Sb(e,t){return e?s6(e)?S.createElement(e,t):e:null}function s6(e){return o6(e)||typeof e=="function"||i6(e)}function o6(e){return typeof e=="function"&&(()=>{const t=Object.getPrototypeOf(e);return t.prototype&&t.prototype.isReactComponent})()}function i6(e){return typeof e=="object"&&typeof e.$$typeof=="symbol"&&["react.memo","react.forward_ref"].includes(e.$$typeof.description)}function a6(e){const t={state:{},onStateChange:()=>{},renderFallbackValue:null,...e},[n]=S.useState(()=>({current:YI(t)})),[r,s]=S.useState(()=>n.current.initialState);return n.current.setOptions(o=>({...o,...e,state:{...r,...e.state},onStateChange:i=>{s(i),e.onStateChange==null||e.onStateChange(i)}})),n.current}const IS=S.forwardRef(({className:e,...t},n)=>c.jsx("div",{className:"relative w-full overflow-auto",children:c.jsx("table",{ref:n,className:ar("w-full caption-bottom text-sm",e),...t})}));IS.displayName="Table";const FS=S.forwardRef(({className:e,...t},n)=>c.jsx("thead",{ref:n,className:ar("[&_tr]:border-b dark:border-white/5",e),...t}));FS.displayName="TableHeader";const zS=S.forwardRef(({className:e,...t},n)=>c.jsx("tbody",{ref:n,className:ar("[&_tr:last-child]:border-0",e),...t}));zS.displayName="TableBody";const l6=S.forwardRef(({className:e,...t},n)=>c.jsx("tfoot",{ref:n,className:ar("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",e),...t}));l6.displayName="TableFooter";const nc=S.forwardRef(({className:e,...t},n)=>c.jsx("tr",{ref:n,className:ar("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted dark:border-white/5 dark:hover:bg-white/5",e),...t}));nc.displayName="TableRow";const VS=S.forwardRef(({className:e,...t},n)=>c.jsx("th",{ref:n,className:ar("h-12 px-4 text-left align-middle font-semibold text-xs uppercase tracking-wider text-gray-600 dark:text-gray-400 [&:has([role=checkbox])]:pr-0 bg-gray-50 dark:bg-white/5",e),...t}));VS.displayName="TableHead";const Wf=S.forwardRef(({className:e,...t},n)=>c.jsx("td",{ref:n,className:ar("p-4 align-middle [&:has([role=checkbox])]:pr-0 text-gray-900 dark:text-gray-300",e),...t}));Wf.displayName="TableCell";const c6=S.forwardRef(({className:e,...t},n)=>c.jsx("caption",{ref:n,className:ar("mt-4 text-sm text-muted-foreground",e),...t}));c6.displayName="TableCaption";function u6({columns:e,data:t,searchable:n=!0,itemsPerPage:r=10,emptyMessage:s="No results."}){var f;const[o,i]=S.useState([]),[a,l]=S.useState([]),[u,d]=S.useState(""),h=a6({data:t,columns:e,getCoreRowModel:XI(),getPaginationRowModel:n6(),onSortingChange:i,getSortedRowModel:r6(),onColumnFiltersChange:l,getFilteredRowModel:t6(),onGlobalFilterChange:d,state:{sorting:o,columnFilters:a,globalFilter:u},initialState:{pagination:{pageSize:r}}});return c.jsxs("div",{className:"space-y-4",children:[n&&c.jsxs("div",{className:"relative",children:[c.jsx(Z1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{placeholder:"Search...",value:u??"",onChange:p=>d(p.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600"})]}),c.jsx("div",{className:"rounded-md border border-gray-200 dark:border-white/10 overflow-hidden",children:c.jsxs(IS,{children:[c.jsx(FS,{children:h.getHeaderGroups().map(p=>c.jsx(nc,{children:p.headers.map(g=>c.jsx(VS,{children:g.isPlaceholder?null:Sb(g.column.columnDef.header,g.getContext())},g.id))},p.id))}),c.jsx(zS,{children:(f=h.getRowModel().rows)!=null&&f.length?h.getRowModel().rows.map(p=>c.jsx(nc,{"data-state":p.getIsSelected()&&"selected",children:p.getVisibleCells().map(g=>c.jsx(Wf,{children:Sb(g.column.columnDef.cell,g.getContext())},g.id))},p.id)):c.jsx(nc,{children:c.jsx(Wf,{colSpan:e.length,className:"h-24 text-center",children:s})})})]})}),h.getPageCount()>1&&c.jsxs("div",{className:"flex items-center justify-between space-x-2 py-4",children:[c.jsxs("div",{className:"text-sm text-gray-700 dark:text-gray-300",children:["Page ",h.getState().pagination.pageIndex+1," of ",h.getPageCount()]}),c.jsxs("div",{className:"flex items-center gap-2",children:[c.jsx("button",{className:"p-2 rounded-lg border border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",onClick:()=>h.previousPage(),disabled:!h.getCanPreviousPage(),children:c.jsx(W1,{size:16})}),c.jsx("button",{className:"p-2 rounded-lg border border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",onClick:()=>h.nextPage(),disabled:!h.getCanNextPage(),children:c.jsx(G1,{size:16})})]})]})]})}function d6(){const{user:e}=Qr(),[t,n]=S.useState([]),[r,s]=S.useState(null),[o,i]=S.useState(!0);S.useEffect(()=>{e&&(async()=>{try{const d=localStorage.getItem("access_token");d&&n([{id:"1",name:"Current API Key",key:d,status:"Active"}])}catch(d){console.error("Failed to fetch API keys:",d)}finally{i(!1)}})()},[e]);const a=(u,d)=>{navigator.clipboard.writeText(u),s(d),setTimeout(()=>s(null),2e3)},l=[{accessorKey:"name",header:"Name"},{accessorKey:"key",header:"Key",cell:({row:u})=>c.jsxs("div",{className:"flex items-center gap-2 font-mono text-gray-700 dark:text-gray-300",children:[c.jsxs("span",{className:"truncate max-w-xs",children:[u.original.key.substring(0,20),"..."]}),c.jsx("button",{onClick:()=>a(u.original.key,u.original.id),className:"p-1 hover:bg-gray-100 dark:hover:bg-white/10 rounded transition-colors",title:"Copy key",children:r===u.original.id?c.jsx(xu,{className:"w-3 h-3 text-green-500"}):c.jsx(q1,{className:"w-3 h-3"})})]})},{accessorKey:"status",header:"Status",cell:({row:u})=>c.jsx("span",{className:`px-2 py-1 rounded-full text-xs font-medium ${u.original.status==="Active"?"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400"}`,children:u.original.status})}];return o?c.jsx("div",{className:"flex items-center justify-center h-64",children:c.jsx("div",{className:"text-gray-500 dark:text-gray-400",children:"Loading API keys..."})}):c.jsxs("div",{className:"max-w-5xl mx-auto space-y-8",children:[c.jsx("div",{className:"flex items-center justify-between",children:c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"API Keys"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Manage your API keys for authentication."})]})}),c.jsx("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:c.jsx(u6,{data:t,columns:l,itemsPerPage:10,searchable:!0,emptyMessage:"No API keys found. Generate one to get started."})}),c.jsxs("div",{className:"bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4",children:[c.jsx("h3",{className:"text-sm font-medium text-blue-900 dark:text-blue-300 mb-2",children:"Using Your API Key"}),c.jsx("p",{className:"text-sm text-blue-700 dark:text-blue-400 mb-3",children:"Include your API key in the Authorization header of your requests:"}),c.jsx("code",{className:"block bg-white dark:bg-black/50 p-3 rounded text-xs font-mono text-gray-900 dark:text-gray-100 border border-blue-200 dark:border-blue-800",children:"Authorization: Bearer YOUR_API_KEY"})]})]})}const h6=["NGO","Government","Private Sector","Research","Individual","Other"],_b=["Health","Agriculture","Energy","Environment","Education","Governance"];function f6(){const{user:e}=Qr(),{theme:t,setTheme:n}=B1(),[r,s]=S.useState({username:(e==null?void 0:e.username)||"",email:(e==null?void 0:e.email)||"",full_name:(e==null?void 0:e.full_name)||"",organization:(e==null?void 0:e.organization)||"",organization_type:(e==null?void 0:e.organization_type)||""}),[o,i]=S.useState((e==null?void 0:e.sector)||[]),[a,l]=S.useState(""),[u,d]=S.useState(""),[h,f]=S.useState(""),[p,g]=S.useState(!1),[m,y]=S.useState({oldPassword:"",newPassword:"",confirmPassword:""}),[x,v]=S.useState(""),[b,k]=S.useState(""),[w,j]=S.useState(!1),[N,_]=S.useState(!1),[P,A]=S.useState(!1),[O,F]=S.useState(!1),D=E=>{i(I=>I.includes(E)?I.filter(K=>K!==E):[...I,E])},U=()=>{const E=a.trim();E&&!o.includes(E)&&(i(I=>[...I,E]),l(""))},W=async E=>{var I,K;E.preventDefault(),f(""),d(""),g(!0);try{await ae.put("/auth/profile",{full_name:r.full_name||void 0,organization:r.organization||void 0,organization_type:r.organization_type||void 0,sector:o.length>0?o:void 0}),d("Profile updated successfully!")}catch(T){f(((K=(I=T.response)==null?void 0:I.data)==null?void 0:K.detail)||"Failed to update profile.")}finally{g(!1)}},M=async E=>{var I,K;if(E.preventDefault(),v(""),k(""),m.newPassword!==m.confirmPassword){v("New passwords do not match");return}j(!0);try{const T=await ae.post("/auth/change-password",{old_password:m.oldPassword,new_password:m.newPassword});T.data.success?(k("Password changed successfully!"),y({oldPassword:"",newPassword:"",confirmPassword:""})):v(T.data.message||"Failed to change password")}catch(T){v(((K=(I=T.response)==null?void 0:I.data)==null?void 0:K.detail)||"Failed to change password")}finally{j(!1)}},H=(e==null?void 0:e.oauth_type)==="Google"||(e==null?void 0:e.oauth_type)==="GitHub",C=!H,L=!H;return c.jsxs("div",{className:"max-w-2xl mx-auto space-y-8",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Account Settings"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Manage your profile and preferences."})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Profile Information"}),c.jsxs("form",{onSubmit:W,className:"space-y-4",children:[h&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:h}),u&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:u}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.username,onChange:E=>s({...r,username:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Full Name"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.full_name,onChange:E=>s({...r,full_name:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",placeholder:"John Doe",disabled:p})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email Address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"email",value:r.email,onChange:E=>s({...r,email:E.target.value}),className:`w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white ${L?"":"opacity-50 cursor-not-allowed"}`,disabled:!L,title:L?"":"Email cannot be changed for OAuth accounts"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization"}),c.jsxs("div",{className:"relative",children:[c.jsx(H1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.organization,onChange:E=>s({...r,organization:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",placeholder:"Organization Name",disabled:p})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("div",{className:"relative",children:[c.jsx($1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsxs("select",{value:r.organization_type,onChange:E=>s({...r,organization_type:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:p,children:[c.jsx("option",{value:"",children:"Select type..."}),h6.map(E=>c.jsx("option",{value:E,children:E},E))]})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Impact Sectors"}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-1",children:[..._b,...o.filter(E=>!_b.includes(E))].map(E=>c.jsxs("button",{type:"button",onClick:()=>D(E),disabled:p,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${o.includes(E)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[E," ",o.includes(E)&&"✓"]},E))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:a,onChange:E=>l(E.target.value),onKeyDown:E=>E.key==="Enter"&&(E.preventDefault(),U()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:p}),c.jsx("button",{type:"button",onClick:U,disabled:p,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Account Type"}),c.jsxs("div",{className:"relative",children:[c.jsx(uR,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:(e==null?void 0:e.account_type)||"Standard",readOnly:!0,className:"w-full pl-9 pr-4 py-2 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none text-gray-500 dark:text-gray-400 cursor-not-allowed"})]})]}),c.jsx("div",{className:"pt-2",children:c.jsx("button",{type:"submit",disabled:p,className:"px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:p?"Saving...":"Save Changes"})})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Appearance"}),c.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[c.jsxs("button",{onClick:()=>n("light"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="light"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(pf,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"Light"})]}),c.jsxs("button",{onClick:()=>n("dark"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="dark"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(ff,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"Dark"})]}),c.jsxs("button",{onClick:()=>n("system"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="system"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(gR,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"System"})]})]})]}),C&&c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Change Password"}),c.jsxs("form",{onSubmit:M,className:"space-y-4",children:[x&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:x}),b&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:b}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Current Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:N?"text":"password",required:!0,placeholder:"••••••••",value:m.oldPassword,onChange:E=>y({...m,oldPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>_(!N),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:N?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:P?"text":"password",placeholder:"••••••••",required:!0,value:m.newPassword,onChange:E=>y({...m,newPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>A(!P),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:P?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:O?"text":"password",required:!0,placeholder:"••••••••",value:m.confirmPassword,onChange:E=>y({...m,confirmPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>F(!O),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:O?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsx("div",{className:"pt-2",children:c.jsx("button",{type:"submit",disabled:w,className:"px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:w?"Changing Password...":"Change Password"})})]})]})]})}function p6({value:e,onChange:t,options:n,placeholder:r="Select...",disabled:s=!1,className:o=""}){const[i,a]=S.useState(!1),[l,u]=S.useState(""),d=S.useRef(null),h=S.useRef(null);S.useEffect(()=>{const m=y=>{d.current&&!d.current.contains(y.target)&&(a(!1),u(""))};return document.addEventListener("mousedown",m),()=>document.removeEventListener("mousedown",m)},[]),S.useEffect(()=>{i&&h.current&&h.current.focus()},[i]);const f=n.filter(m=>m.toLowerCase().includes(l.toLowerCase())),p=m=>{t(m),a(!1),u("")},g=m=>{m.stopPropagation(),t(""),u("")};return c.jsxs("div",{className:`relative ${o}`,ref:d,children:[c.jsxs("button",{type:"button",onClick:()=>!s&&a(!i),disabled:s,className:"flex items-center justify-between w-full min-w-[240px] px-3 py-2 text-sm bg-white dark:bg-secondary border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white disabled:opacity-50 disabled:cursor-not-allowed",children:[c.jsx("span",{className:e?"text-gray-900 dark:text-white":"text-gray-400 dark:text-gray-500",children:e||r}),c.jsxs("div",{className:"flex items-center gap-1 ml-2",children:[e&&c.jsx(wu,{size:14,className:"text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 cursor-pointer",onClick:g}),c.jsx(U1,{size:16,className:`text-gray-400 transition-transform ${i?"rotate-180":""}`})]})]}),i&&c.jsxs("div",{className:"absolute z-50 w-full mt-1 bg-white dark:bg-secondary border border-gray-200 dark:border-white/10 rounded-lg shadow-lg overflow-hidden",children:[c.jsx("div",{className:"p-2 border-b border-gray-200 dark:border-white/10",children:c.jsxs("div",{className:"relative",children:[c.jsx(Z1,{size:14,className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400"}),c.jsx("input",{ref:h,type:"text",value:l,onChange:m=>u(m.target.value),placeholder:"Search...",className:"w-full pl-8 pr-3 py-1.5 text-sm bg-gray-50 dark:bg-black/30 border border-gray-200 dark:border-white/10 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:text-white placeholder-gray-400"})]})}),c.jsx("div",{className:"max-h-60 overflow-y-auto",children:f.length===0?c.jsx("div",{className:"px-3 py-4 text-sm text-gray-400 text-center",children:"No results found"}):f.map(m=>c.jsx("button",{onClick:()=>p(m),className:`w-full text-left px-3 py-2 text-sm transition-colors ${m===e?"bg-primary-50 text-primary-600 dark:bg-primary-900/20 dark:text-primary-400":"text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/5"}`,children:m},m))})]})]})}const g6=[{label:"Overview",value:"overview"},{label:"By Organization",value:"organization"},{label:"By Org Type",value:"organization_type"},{label:"By Sector",value:"sector"}];function m6({view:e,onViewChange:t,filterValue:n,onFilterValueChange:r,filters:s,filtersLoading:o}){const a=s?e==="organization"?s.organizations:e==="organization_type"?s.organization_types:e==="sector"?s.sectors:[]:[],l=e!=="overview",u=()=>e==="organization"?"Organization":e==="organization_type"?"Organization Type":e==="sector"?"Sector":"";return c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-3",children:[c.jsx("div",{className:"flex items-center gap-1 bg-white dark:bg-secondary rounded-lg border border-gray-200 dark:border-white/10 p-1",children:g6.map(d=>c.jsx("button",{onClick:()=>{t(d.value),r("")},className:`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${e===d.value?"bg-primary-600 text-white":"text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-white/5"}`,children:d.label},d.value))}),l&&c.jsx(p6,{value:n,onChange:r,options:a,placeholder:`Select ${u()}...`,disabled:o||a.length===0})]})}function y6(){const[e,t]=S.useState(null),[n,r]=S.useState(!0);return S.useEffect(()=>{(async()=>{var o,i,a;try{const l=await ae.get("/api/admin/analytics/filters");t(l.data)}catch(l){_n.error(((a=(i=(o=l.response)==null?void 0:o.data)==null?void 0:i.detail)==null?void 0:a.message)||"Failed to fetch filter options")}finally{r(!1)}})()},[]),{filters:e,loading:n}}function x6(e,t,n="7d"){const[r,s]=S.useState(null),[o,i]=S.useState(!0),[a,l]=S.useState(null),u=S.useCallback(async()=>{var d,h,f;i(!0),l(null);try{let p="/api/admin/analytics/";const g=new URLSearchParams({time_range:n});e==="overview"?p+="overview":e==="organization"?(p+="by-organization",g.set("organization",t)):e==="organization_type"?(p+="by-organization-type",g.set("organization_type",t)):e==="sector"&&(p+="by-sector",g.set("sector",t));const m=await ae.get(`${p}?${g.toString()}`);s(m.data)}catch(p){const g=((f=(h=(d=p.response)==null?void 0:d.data)==null?void 0:h.detail)==null?void 0:f.message)||"Failed to fetch analytics data";l(g),_n.error(g)}finally{i(!1)}},[e,t,n]);return S.useEffect(()=>{e==="overview"||t?u():(s(null),i(!1))},[e,t,n,u]),{data:r,loading:o,error:a}}function b6(){return{exportCSV:async(t,n,r)=>{try{const s=new URLSearchParams({view:t,time_range:n});t==="organization"&&r?s.set("organization",r):t==="organization_type"&&r?s.set("organization_type",r):t==="sector"&&r&&s.set("sector",r);const o=await ae.get(`/api/admin/analytics/export?${s.toString()}`,{responseType:"blob"}),i=new Blob([o.data],{type:"text/csv"}),a=window.URL.createObjectURL(i),l=document.createElement("a");l.href=a,l.download=`analytics_${t}_${n}.csv`,document.body.appendChild(l),l.click(),document.body.removeChild(l),window.URL.revokeObjectURL(a),_n.success("CSV exported successfully")}catch{_n.error("Failed to export CSV")}}}}Bs.register(Fo,zo,Cs,bn,Iu,Fu,Du,Ou);const jb=["#E6194B","#3CB44B","#4363D8","#F58231","#911EB4","#42D4F4","#F032E6","#469990","#9A6324","#800000","#808000","#000075","#000000"];function v6(){var P,A,O,F,D,U,W,M,H,C,L,E,I,K;const[e,t]=S.useState("7d"),[n,r]=S.useState("overview"),[s,o]=S.useState(""),{filters:i,loading:a}=y6(),{data:l,loading:u}=x6(n,s,e),{exportCSV:d}=b6(),h=S.useMemo(()=>{var $;const T={Total:"#6B7280"};return($=l==null?void 0:l.endpoint_chart_data)!=null&&$.datasets&&Object.keys(l.endpoint_chart_data.datasets).sort().forEach((ne,ce)=>{T[ne]=jb[ce%jb.length]}),T},[l]),[f,p]=S.useState({Total:!0});S.useEffect(()=>{var T;(T=l==null?void 0:l.endpoint_chart_data)!=null&&T.datasets&&p($=>{const G={...$};return Object.keys(l.endpoint_chart_data.datasets).forEach(ne=>{G[ne]===void 0&&(G[ne]=!0)}),G})},[l]);const g=S.useMemo(()=>{var $;const T=[{label:"Total",value:"Total",color:h.Total}];return($=l==null?void 0:l.endpoint_chart_data)!=null&&$.datasets&&Object.keys(l.endpoint_chart_data.datasets).sort().forEach(G=>{T.push({label:G.replace("/v1/",""),value:G,color:h[G]})}),T},[l,h]),m=S.useMemo(()=>Object.keys(f).filter(T=>f[T]!==!1),[f]),y=T=>{const $={};g.forEach(G=>{$[G.value]=T.includes(G.value)}),p($)},x=((P=l==null?void 0:l.endpoint_chart_data)==null?void 0:P.datasets)||{},v={labels:((A=l==null?void 0:l.endpoint_chart_data)==null?void 0:A.labels)||((O=l==null?void 0:l.chart_data)==null?void 0:O.labels)||[],datasets:[...Object.entries(x).map(([T,$])=>({label:T,data:$,borderColor:h[T]||"#6B7280",backgroundColor:"transparent",tension:.4,borderWidth:2,hidden:f[T]===!1})),{label:"Total",data:((F=l==null?void 0:l.chart_data)==null?void 0:F.data)||[],borderColor:"#6B7280",backgroundColor:"transparent",borderWidth:3,tension:.4,hidden:f.Total===!1}]},b={labels:((D=l==null?void 0:l.latency_chart)==null?void 0:D.labels)||[],datasets:[{label:"Avg Latency (ms)",data:((W=(U=l==null?void 0:l.latency_chart)==null?void 0:U.data)==null?void 0:W.map(T=>T*1e3))||[],fill:!0,backgroundColor:T=>{const G=T.chart.ctx.createLinearGradient(0,0,0,200);return G.addColorStop(0,"rgba(59, 130, 246, 0.2)"),G.addColorStop(1,"rgba(59, 130, 246, 0)"),G},borderColor:"#3b82f6",tension:.4}]},k={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{mode:"index",intersect:!1,backgroundColor:"rgba(0, 0, 0, 0.8)",titleColor:"#fff",bodyColor:"#fff",borderColor:"rgba(255, 255, 255, 0.1)",borderWidth:1,padding:10}},scales:{x:{grid:{display:!1},ticks:{color:"rgba(156, 163, 175, 0.8)"}},y:{grid:{color:"rgba(156, 163, 175, 0.1)"},ticks:{color:"rgba(156, 163, 175, 0.8)"},beginAtZero:!0}},interaction:{mode:"nearest",axis:"x",intersect:!1}},w=((M=l==null?void 0:l.usage)==null?void 0:M.reduce((T,$)=>T+$.used,0))||0,j=(C=(H=l==null?void 0:l.latency_chart)==null?void 0:H.data)!=null&&C.length?(l.latency_chart.data.reduce((T,$)=>T+$,0)/l.latency_chart.data.length*1e3).toFixed(0):"0",N=(L=l==null?void 0:l.usage)==null?void 0:L.reduce((T,$)=>$.used>((T==null?void 0:T.used)||0)?$:T,null),_=((E=i==null?void 0:i.organizations)==null?void 0:E.length)||0;return u&&!l?c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col gap-4",children:[c.jsx(ge,{className:"h-8 w-48 mb-2"}),c.jsx(ge,{className:"h-10 w-full max-w-xl"})]}),c.jsx("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[1,2,3,4].map(T=>c.jsxs("div",{className:"bg-white dark:bg-secondary p-6 rounded-xl border border-gray-200 dark:border-white/5 shadow-sm",children:[c.jsx(ge,{className:"h-8 w-8 rounded-lg mb-4"}),c.jsx(ge,{className:"h-8 w-32 mb-1"}),c.jsx(ge,{className:"h-3 w-16"})]},T))}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Admin Analytics"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Platform-wide API usage and performance analytics."})]}),c.jsxs("button",{onClick:()=>d(n,e,s),className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium",children:[c.jsx(K1,{size:16}),"Export CSV"]})]}),c.jsx(m6,{view:n,onViewChange:r,filterValue:s,onFilterValueChange:o,filters:i,filtersLoading:a}),n!=="overview"&&!s&&c.jsxs("div",{className:"text-center py-12 text-gray-500 dark:text-gray-400",children:[c.jsx(U0,{size:48,className:"mx-auto mb-4 opacity-50"}),c.jsx("p",{className:"text-lg font-medium",children:"Select a filter value above to view analytics"})]}),(n==="overview"||s)&&l&&c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Total Requests",value:w.toLocaleString(),icon:yu,color:"bg-blue-500"}),c.jsx(kt,{label:"Avg Latency",value:`${j}ms`,icon:bu,color:"bg-orange-500"}),c.jsx(kt,{label:"Most Used",value:((I=N==null?void 0:N.endpoint)==null?void 0:I.replace("/v1/",""))||"N/A",icon:og,color:"bg-purple-500"}),c.jsx(kt,{label:"Organizations",value:_,icon:U0,color:"bg-green-500"})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsx("div",{className:"lg:col-span-2",children:c.jsxs(Ms,{title:"Request Volume by Endpoint",description:"Track usage trends across all users",showTimeSelector:!0,timeRange:e,onTimeRangeChange:t,className:"h-[400px]",children:[c.jsx("div",{className:"flex flex-wrap gap-3 mb-4 pb-4 border-b border-gray-200 dark:border-white/10",children:c.jsx(S2,{label:"Select Endpoints",options:g,selected:m,onChange:y})}),c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:k,data:v})})]})}),c.jsx(Ms,{title:"Latency Trends",description:"Average response time over the selected period",showTimeSelector:!0,timeRange:e,onTimeRangeChange:t,children:c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:k,data:b})})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Endpoint Breakdown"}),c.jsx("div",{className:"space-y-3",children:(K=l==null?void 0:l.usage)==null?void 0:K.filter(T=>T.endpoint!=="unknown").sort((T,$)=>$.used-T.used).map(T=>{const $=w>0?(T.used/w*100).toFixed(1):"0";return c.jsxs("div",{className:"flex items-center justify-between",children:[c.jsxs("div",{className:"flex items-center gap-3 flex-1",children:[c.jsx("div",{className:"w-3 h-3 rounded-full flex-shrink-0",style:{backgroundColor:h[T.endpoint]||"#6B7280"}}),c.jsx("span",{className:"text-sm text-gray-700 dark:text-gray-300",children:T.endpoint.replace("/tasks/","").replace("/tasks","tasks")})]}),c.jsxs("div",{className:"flex items-center gap-4",children:[c.jsx("span",{className:"text-sm font-medium text-gray-900 dark:text-white",children:T.used.toLocaleString()}),c.jsxs("span",{className:"text-sm text-gray-500 dark:text-gray-400 w-12 text-right",children:[$,"%"]})]})]},T.endpoint)})})]})]}),(l==null?void 0:l.per_user_breakdown)&&l.per_user_breakdown.length>0&&c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:[c.jsxs("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:["User Breakdown — ",l.organization]}),c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10",children:[c.jsx("th",{className:"text-left py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Username"}),c.jsx("th",{className:"text-right py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Total Requests"}),c.jsx("th",{className:"text-left py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Top Endpoints"})]})}),c.jsx("tbody",{children:l.per_user_breakdown.map(T=>{const $=Object.entries(T.endpoints).sort(([,G],[,ne])=>ne-G).slice(0,3);return c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-3 px-4 text-gray-900 dark:text-white font-medium",children:T.username}),c.jsx("td",{className:"py-3 px-4 text-right text-gray-900 dark:text-white",children:T.total_requests.toLocaleString()}),c.jsx("td",{className:"py-3 px-4",children:c.jsx("div",{className:"flex flex-wrap gap-1",children:$.map(([G,ne])=>c.jsxs("span",{className:"inline-flex items-center px-2 py-0.5 rounded text-xs bg-gray-100 dark:bg-white/10 text-gray-700 dark:text-gray-300",children:[G.replace("/tasks/",""),": ",ne]},G))})})]},T.username)})})]})})]})]})]})}const BS="/api/admin/analytics/billing";function $S(e,t={}){return new URLSearchParams({category:e.category,provider:e.provider,range:e.range,resolution:e.resolution,...t})}function $a(e,t,n={}){const[r,s]=S.useState(null),[o,i]=S.useState(!0),a=JSON.stringify(n),l=S.useCallback(async()=>{var u,d;i(!0);try{const h=$S(t,JSON.parse(a)),f=await ae.get(`${BS}${e}?${h.toString()}`);s(f.data)}catch(h){const f=h;_n.error(((d=(u=f.response)==null?void 0:u.data)==null?void 0:d.message)||`Failed to load ${e}`)}finally{i(!1)}},[e,t.category,t.provider,t.range,t.resolution,a]);return S.useEffect(()=>{l()},[l]),{data:r,loading:o}}const w6=e=>$a("/summary",e),k6=e=>$a("/timeseries",e,{group_by:e.groupBy||"provider"}),S6=e=>$a("/providers",e),_6=(e,t,n,r)=>$a("/table",e,{page:String(t),page_size:"50",sort:n,sort_dir:r,...e.search?{search:e.search}:{}}),j6=(e,t)=>$a("/breakdown",e,{group_by:t});function C6(){return{exportCSV:async t=>{try{const n=$S(t),r=await ae.get(`${BS}/export?${n.toString()}`,{responseType:"blob"}),s=window.URL.createObjectURL(new Blob([r.data],{type:"text/csv"})),o=document.createElement("a");o.href=s,o.download=`billing_${t.provider}_${t.resolution}.csv`,document.body.appendChild(o),o.click(),document.body.removeChild(o),window.URL.revokeObjectURL(s),_n.success("CSV exported")}catch{_n.error("Failed to export CSV")}}}}Bs.register(Fo,zo,Cs,bn,Ci,Iu,Fu,Du,Ou);const N6=[["today","Today"],["yesterday","Yesterday"],["last_7_days","Last 7 Days"],["last_30_days","Last 30 Days"],["last_90_days","Last 90 Days"],["this_month","This Month"],["last_month","Last Month"]],Cb={runpod:"#4363D8",modal:"#F58231",vastai:"#16A34A"},Nb=["#E6194B","#3CB44B","#4363D8","#F58231","#911EB4","#42D4F4","#F032E6","#469990","#9A6324","#800000"];function P6(){var D,U,W,M,H;const[e,t]=S.useState({category:"inference",provider:"all",range:"last_30_days",resolution:"day"}),[n,r]=S.useState(1),[s,o]=S.useState("cost"),[i,a]=S.useState("desc"),[l,u]=S.useState("object"),[d,h]=S.useState(""),{data:f,loading:p}=w6(e),{data:g}=k6(e),{data:m}=S6(e),{data:y}=_6(e,n,s,i),x=e.category==="cloud"?l:"object",{data:v}=j6(e,x),{exportCSV:b}=C6(),k=((v==null?void 0:v.rows)||[]).filter(C=>C.key.toLowerCase().includes(d.toLowerCase())),w=k.reduce((C,L)=>C+L.cost,0),j=C=>{t(L=>({...L,...C})),r(1)},N=C=>{s===C?a(L=>L==="asc"?"desc":"asc"):(o(C),a("desc")),r(1)},_=C=>s===C?i==="asc"?" ▲":" ▼":"",P=(g==null?void 0:g.cost_by_group)||{},A={labels:(g==null?void 0:g.labels)||[],datasets:[...Object.entries(P).map(([C,L],E)=>({label:C,data:L,borderColor:Cb[C]||Nb[E%Nb.length],backgroundColor:"transparent",borderWidth:2,tension:.4})),{label:"Total",data:(g==null?void 0:g.cost)||[],borderColor:"#6B7280",backgroundColor:"transparent",borderWidth:3,borderDash:[5,5],tension:.4}]},O={labels:(m==null?void 0:m.labels)||[],datasets:[{data:(m==null?void 0:m.cost)||[],backgroundColor:((m==null?void 0:m.labels)||[]).map(C=>Cb[C]||"#6B7280")}]},F={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!0,labels:{color:"rgba(156,163,175,0.9)"}}},scales:{x:{grid:{display:!1},ticks:{color:"rgba(156,163,175,0.8)"}},y:{grid:{color:"rgba(156,163,175,0.1)"},beginAtZero:!0,ticks:{color:"rgba(156,163,175,0.8)"}}}};return p&&!f?c.jsxs("div",{className:"space-y-6",children:[c.jsx(ge,{className:"h-8 w-64"}),c.jsx("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[1,2,3,4].map(C=>c.jsx(ge,{className:"h-28 rounded-xl"},C))}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Infrastructure Billing"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:e.category==="training"?"Vast.ai training spend, GPU hours, and per-job breakdown.":e.category==="cloud"?"AWS spend by service and usage type, from Cost Explorer.":"Runpod & Modal spend, runtime, and storage analytics."})]}),c.jsxs("button",{onClick:()=>b(e),className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 text-sm font-medium",children:[c.jsx(K1,{size:16})," Export CSV"]})]}),c.jsx("div",{className:"flex gap-1 border-b border-gray-200 dark:border-white/10",children:[["inference","Inference (Runpod & Modal)",!1],["training","Training (Vast.ai)",!1],["cloud","Cloud (AWS)",!1]].map(([C,L,E])=>c.jsx("button",{disabled:E,onClick:()=>{t(I=>({...I,category:C,provider:"all",groupBy:C==="cloud"?"object":void 0})),r(1)},className:"px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors "+(E?"text-gray-300 dark:text-gray-600 cursor-not-allowed border-transparent":e.category===C?"border-primary-600 text-primary-700 dark:text-primary-400":"border-transparent text-gray-500 hover:text-gray-800 dark:hover:text-gray-200"),children:L},C))}),c.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.category==="inference"&&c.jsxs("select",{value:e.provider,onChange:C=>j({provider:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:[c.jsx("option",{value:"all",children:"All Platforms"}),c.jsx("option",{value:"runpod",children:"Runpod"}),c.jsx("option",{value:"modal",children:"Modal"})]}),c.jsx("select",{value:e.range,onChange:C=>j({range:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:N6.map(([C,L])=>c.jsx("option",{value:C,children:L},C))}),c.jsx("select",{value:e.resolution,onChange:C=>j({resolution:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:["hour","day","week","month","year"].map(C=>c.jsx("option",{value:C,children:C[0].toUpperCase()+C.slice(1)},C))})]}),(D=f==null?void 0:f.warnings)==null?void 0:D.map(C=>c.jsx("div",{className:"text-sm text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 px-4 py-2 rounded-lg",children:C},C)),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Total Spend",value:`$${((f==null?void 0:f.total_spend)||0).toFixed(2)}`,icon:W0,color:"bg-blue-500"}),c.jsx(kt,{label:"Avg Daily Spend",value:`$${((f==null?void 0:f.avg_daily_spend)||0).toFixed(2)}`,icon:W0,color:"bg-green-500"}),c.jsx(kt,{label:"GPU Hours",value:`${(((f==null?void 0:f.total_runtime_ms)||0)/36e5).toFixed(1)}h`,icon:bu,color:"bg-orange-500"}),c.jsx(kt,{label:"Avg Storage",value:`${((f==null?void 0:f.avg_storage_gb)||0).toFixed(0)} GB`,icon:fR,color:"bg-purple-500"})]}),c.jsxs("details",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-4 text-sm text-gray-600 dark:text-gray-300",children:[c.jsxs("summary",{className:"flex items-center gap-2 cursor-pointer font-medium text-gray-900 dark:text-white",children:[c.jsx(sg,{size:16})," What these numbers mean & how they're computed"]}),c.jsxs("div",{className:"mt-3 space-y-2 leading-relaxed",children:[c.jsxs("p",{children:[c.jsx("b",{children:"Total / Avg Daily Spend"})," — USD billed by the provider for the selected range and platform(s), summed across all records. Modal amounts are pre-credit (before any credits or reservations), so your invoice may be lower."]}),c.jsxs("p",{children:[c.jsx("b",{children:"GPU Hours"})," — total billed run time, from Runpod's ",c.jsx("code",{children:"timeBilledMs"}),"(worker-time across the period). Modal bills per-app cost and does not report a runtime, so this reflects Runpod only."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Avg Storage (GB)"})," — providers bill storage as ",c.jsx("b",{children:"GB-hours"})," (capacity × hours billed), so a steady 350 GB volume reports 350 × 24 = 8,400 per day. We show the time-weighted average — total GB-hours ÷ hours in the range — as actual provisioned GB. The records table and CSV show the raw per-bucket GB-hours."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Active Endpoints / Modal Apps"})," — distinct Runpod endpoints and Modal apps with billing in the range. ",c.jsx("b",{children:"Network Volumes"})," are account-level storage, not an endpoint, so they're excluded from this count (but included in spend/storage)."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Network Volumes"})," — Runpod persistent network storage cost (",c.jsx("code",{children:"/billing/networkvolumes"}),"), shown as its own row and folded into totals."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Cost Over Time"})," — per-bucket spend with a line per platform plus a dashed Total. Buckets roll up to the selected resolution (hour → year)."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Training (Vast.ai)"})," — Vast.ai bills per contract (a whole job), not per day. We spread each contract's cost and GPU-hours evenly across the days it ran so the charts and totals are smooth and correct; the Training Jobs table lists one row per contract (job/instance) with its total GPU-hours and cost. Storage is billed as cost (not GB), so it appears in spend rather than the storage figure."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Cloud (AWS)"})," — AWS costs come from Cost Explorer (UnblendedCost), broken down by service and usage type. The graph shows cost per service over time; the table toggles between Service and Usage-type and is searchable. Hourly granularity is limited by AWS to the last 14 days. Cost Explorer bills per API request, so figures are cached briefly."]}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400",children:"Scope & freshness: Runpod is scoped to the configured endpoints; Modal covers the whole workspace. Figures are cached briefly for consistency, so very recent usage settles within the cache window."})]})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsx("div",{className:"lg:col-span-2",children:c.jsx(Ms,{title:"Cost Over Time",description:"Spend per bucket across selected platforms",className:"h-[400px]",children:c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:F,data:A})})})}),c.jsx(Ms,{title:"Spend by Platform",description:e.category==="cloud"?"AWS":e.category==="training"?"Vast.ai":"Runpod vs Modal",children:c.jsx("div",{className:"flex-1 min-h-0 flex items-center justify-center",children:c.jsx(lI,{data:O,options:{responsive:!0,maintainAspectRatio:!1}})})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Highlights"}),c.jsxs("ul",{className:"text-sm text-gray-700 dark:text-gray-300 space-y-2",children:[e.category==="training"?c.jsxs("li",{children:["Active jobs/instances: ",c.jsx("b",{children:(f==null?void 0:f.active_instances)??0})]}):e.category==="cloud"?c.jsxs("li",{children:["Active services: ",c.jsx("b",{children:(f==null?void 0:f.active_services)??0})]}):c.jsxs(c.Fragment,{children:[c.jsxs("li",{children:["Active endpoints: ",c.jsx("b",{children:(f==null?void 0:f.active_endpoints)??0})]}),c.jsxs("li",{children:["Active Modal apps: ",c.jsx("b",{children:(f==null?void 0:f.active_modal_apps)??0})]})]}),c.jsxs("li",{children:["Top endpoint: ",c.jsx("b",{children:((U=f==null?void 0:f.highest_cost_endpoint)==null?void 0:U.name)??"N/A"})," ($",(((W=f==null?void 0:f.highest_cost_endpoint)==null?void 0:W.cost)??0).toFixed(2),")"]}),c.jsxs("li",{children:["Top platform: ",c.jsx("b",{children:((M=f==null?void 0:f.highest_cost_platform)==null?void 0:M.name)??"N/A"})," ($",(((H=f==null?void 0:f.highest_cost_platform)==null?void 0:H.cost)??0).toFixed(2),")"]})]})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-6",children:[c.jsxs("div",{className:"flex items-center justify-between mb-4",children:[c.jsxs("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2",children:[c.jsx(SR,{size:18})," ",e.category==="cloud"?"AWS Cost & Usage":e.category==="training"?"Training Jobs":"Billing Records"]}),e.category==="inference"&&c.jsx("input",{type:"text",placeholder:"Search object / GPU / env...",onChange:C=>j({search:C.target.value||void 0}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm"})]}),c.jsx("div",{className:"overflow-x-auto",children:e.category==="cloud"?c.jsxs("div",{children:[c.jsxs("div",{className:"flex items-center justify-between mb-3 gap-3",children:[c.jsx("div",{className:"flex gap-1",children:["object","usage_type"].map(C=>c.jsx("button",{onClick:()=>u(C),className:"px-3 py-1 rounded text-sm "+(l===C?"bg-primary-600 text-white":"bg-gray-100 dark:bg-white/10 text-gray-700 dark:text-gray-300"),children:C==="object"?"By Service":"By Usage Type"},C))}),c.jsx("input",{type:"text",value:d,placeholder:"Search service / usage type...",onChange:C=>h(C.target.value),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm"})]}),c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:l==="object"?"Service":"Usage Type"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Cost"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Share"})]})}),c.jsx("tbody",{children:k.map(C=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.key}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(2)]}),c.jsxs("td",{className:"py-2 px-3 text-right",children:[w>0?(C.cost/w*100).toFixed(1):"0.0","%"]})]},C.key))})]})]}):e.category==="training"?c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:"Job / Instance"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"GPU Hours"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Cost"})]})}),c.jsx("tbody",{children:((v==null?void 0:v.rows)||[]).map(C=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.key}),c.jsxs("td",{className:"py-2 px-3 text-right",children:[(C.runtime_ms/36e5).toFixed(1),"h"]}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(3)]})]},C.key))})]}):c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:"Provider"}),c.jsx("th",{className:"py-2 px-3",children:"Object"}),c.jsxs("th",{className:"py-2 px-3 cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200",onClick:()=>N("timestamp"),children:["Date",_("timestamp")]}),c.jsxs("th",{className:"py-2 px-3 text-right cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200",onClick:()=>N("cost"),children:["Cost",_("cost")]}),c.jsx("th",{className:"py-2 px-3",children:"GPU"}),c.jsx("th",{className:"py-2 px-3",children:"Env"})]})}),c.jsx("tbody",{children:((y==null?void 0:y.rows)||[]).map((C,L)=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.provider}),c.jsx("td",{className:"py-2 px-3",children:C.object_name}),c.jsx("td",{className:"py-2 px-3",children:C.timestamp.slice(0,10)}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(4)]}),c.jsx("td",{className:"py-2 px-3",children:C.gpu||"-"}),c.jsx("td",{className:"py-2 px-3",children:C.environment||"-"})]},`${C.provider}-${C.object_name}-${C.timestamp}-${L}`))})]})}),e.category==="inference"&&c.jsxs("div",{className:"flex items-center justify-between mt-4 text-sm text-gray-500 dark:text-gray-400",children:[c.jsxs("span",{children:[(y==null?void 0:y.total)??0," records"]}),c.jsxs("div",{className:"flex gap-2",children:[c.jsx("button",{disabled:n<=1,onClick:()=>r(C=>C-1),className:"px-3 py-1 rounded border border-gray-200 dark:border-white/10 disabled:opacity-40",children:"Prev"}),c.jsx("button",{disabled:!y||n*y.page_size>=y.total,onClick:()=>r(C=>C+1),className:"px-3 py-1 rounded border border-gray-200 dark:border-white/10 disabled:opacity-40",children:"Next"})]})]})]})]})}const Gf="/api/admin/google-analytics";function R6(){const[e,t]=S.useState([]),[n,r]=S.useState(!0),[s,o]=S.useState(!1);return S.useEffect(()=>{let i=!1;return(async()=>{var a;try{const{data:l}=await ae.get(`${Gf}/properties`);i||t(l.properties)}catch(l){((a=l==null?void 0:l.response)==null?void 0:a.status)===503?i||o(!0):_n.error("Failed to load GA properties")}finally{i||r(!1)}})(),()=>{i=!0}},[]),{properties:e,loading:n,notConfigured:s}}function E6(e,t){const[n,r]=S.useState(null),[s,o]=S.useState(!1),[i,a]=S.useState(null),l=S.useCallback(async(u=!1)=>{var d,h;if(e){o(!0),a(null);try{const f=u?`${Gf}/refresh`:`${Gf}/overview`,{data:p}=await ae({method:u?"post":"get",url:f,params:{property_id:e,time_range:t}});r(p)}catch(f){const p=((h=(d=f==null?void 0:f.response)==null?void 0:d.data)==null?void 0:h.detail)||"Failed to load analytics";a(typeof p=="string"?p:"Failed to load analytics"),_n.error(typeof p=="string"?p:"Failed to load analytics")}finally{o(!1)}}},[e,t]);return S.useEffect(()=>{l(!1)},[l]),{data:n,loading:s,error:i,refresh:()=>l(!0)}}function T6({series:e}){const t={labels:e.labels,datasets:[{label:"Active users",data:e.active_users,borderColor:"#3b82f6",backgroundColor:"rgba(59,130,246,0.15)",tension:.4},{label:"New users",data:e.new_users,borderColor:"#10b981",backgroundColor:"rgba(16,185,129,0.1)",tension:.4},{label:"Sessions",data:e.sessions,borderColor:"#f59e0b",backgroundColor:"rgba(245,158,11,0.1)",tension:.4}]},n={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"top"}},interaction:{mode:"index",intersect:!1},scales:{y:{beginAtZero:!0,grid:{color:"rgba(156,163,175,0.1)"}},x:{grid:{display:!1}}}};return c.jsx("div",{className:"h-[300px]",children:c.jsx(Vo,{data:t,options:n})})}function A6({pages:e}){return e.length?c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Page"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Views"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Avg duration"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsxs("td",{className:"py-2 px-3",children:[c.jsx("div",{className:"font-medium text-gray-900 dark:text-white",children:t.title||t.path}),c.jsx("div",{className:"text-xs text-gray-500 dark:text-gray-400",children:t.path})]}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.views.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.users.toLocaleString()}),c.jsxs("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:[t.avg_duration.toFixed(1),"s"]})]},t.path))})]})}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No page views in this range."})}function nh({title:e,rows:t}){const n=t.reduce((r,s)=>r+s.users,0);return c.jsxs("div",{children:[c.jsx("h4",{className:"text-sm font-semibold text-gray-700 dark:text-gray-200 mb-2",children:e}),t.length===0?c.jsx("p",{className:"text-xs text-gray-500",children:"No data."}):c.jsx("ul",{className:"space-y-1",children:t.map(r=>{const s=n?(r.users/n*100).toFixed(1):"0";return c.jsxs("li",{className:"flex items-center justify-between text-sm",children:[c.jsx("span",{className:"text-gray-700 dark:text-gray-300",children:r.label}),c.jsxs("span",{className:"text-gray-900 dark:text-white font-medium",children:[r.users.toLocaleString()," ",c.jsxs("span",{className:"text-xs text-gray-500",children:["(",s,"%)"]})]})]},r.label)})})]})}function M6({platforms:e}){return c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-6",children:[c.jsx(nh,{title:"Device",rows:e.device}),c.jsx(nh,{title:"Operating system",rows:e.os}),c.jsx(nh,{title:"Browser",rows:e.browser})]})}function L6({rows:e}){return e.length?c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Country"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"City"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Sessions"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-2 px-3 text-gray-900 dark:text-white",children:t.country||"—"}),c.jsx("td",{className:"py-2 px-3 text-gray-700 dark:text-gray-300",children:t.city||"—"}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.users.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:t.sessions.toLocaleString()})]},`${t.country}-${t.city}`))})]})}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No geographic data."})}function O6({events:e}){return e.length?c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Event"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Count"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-2 px-3 text-gray-900 dark:text-white font-mono text-xs",children:t.name}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.count.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:t.users.toLocaleString()})]},t.name))})]}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No events in this range."})}Bs.register(Fo,zo,Cs,bn,Iu,Fu,Du,Ou);const D6=[{label:"Last 24h",value:"24h"},{label:"Last 7 days",value:"7d"},{label:"Last 30 days",value:"30d"},{label:"Last 60 days",value:"60d"},{label:"Last 90 days",value:"90d"}];function I6(){const{properties:e,loading:t,notConfigured:n}=R6(),[r,s]=m1(),o=r.get("property")||"",i=r.get("range")||"7d";S.useEffect(()=>{!o&&e.length>0&&s({property:e[0].id,range:i},{replace:!0})},[e,o,i,s]);const{data:a,loading:l,error:u,refresh:d}=E6(o,i),h=S.useMemo(()=>{if(!a)return null;const f=g=>g.reduce((m,y)=>m+y,0),p=g=>g.length?f(g)/g.length:0;return{users:f(a.traffic.active_users),sessions:f(a.traffic.sessions),engagementRate:p(a.traffic.engagement_rate),avgSessionSec:p(a.traffic.avg_session_duration)}},[a]);return n?c.jsx("div",{className:"text-center py-12",children:c.jsxs("p",{className:"text-gray-500 dark:text-gray-400",children:["Google Analytics is not configured. See ",c.jsx("code",{children:"docs/google-analytics.md"}),"."]})}):t?c.jsxs("div",{className:"space-y-6",children:[c.jsx(ge,{className:"h-8 w-48"}),c.jsx(ge,{className:"h-10 w-full max-w-xl"}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Google Analytics"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Site & app analytics for Sunbird properties."})]}),c.jsxs("button",{onClick:()=>{d(),_n.info("Refreshing from Google Analytics…")},disabled:l,className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 disabled:opacity-50 transition-colors text-sm font-medium",children:[c.jsx(kR,{size:16,className:l?"animate-spin":""}),"Refresh"]})]}),c.jsxs("div",{className:"flex flex-wrap gap-3 items-center",children:[c.jsx("select",{value:o,onChange:f=>s({property:f.target.value,range:i}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:e.map(f=>c.jsx("option",{value:f.id,children:f.name},f.id))}),c.jsx("select",{value:i,onChange:f=>s({property:o,range:f.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:D6.map(f=>c.jsx("option",{value:f.value,children:f.label},f.value))}),a&&c.jsxs("span",{className:"text-xs text-gray-500 dark:text-gray-400 ml-auto",children:["Cached until ",new Date(a.cached_until).toLocaleTimeString()]})]}),l&&!a&&c.jsx(ge,{className:"h-[400px] w-full rounded-xl"}),u&&!a&&c.jsx("div",{className:"p-4 rounded-lg bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 text-sm",children:u}),a&&h&&c.jsxs(c.Fragment,{children:[a.partial&&c.jsxs("div",{className:"p-3 rounded-lg bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-200 text-sm",children:["Some reports failed to load: ",a.failed_reports.join(", "),"."]}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Users",value:h.users.toLocaleString(),icon:ek,color:"bg-blue-500"}),c.jsx(kt,{label:"Sessions",value:h.sessions.toLocaleString(),icon:yu,color:"bg-orange-500"}),c.jsx(kt,{label:"Engagement",value:`${(h.engagementRate*100).toFixed(1)}%`,icon:og,color:"bg-purple-500"}),c.jsx(kt,{label:"Avg session",value:`${h.avgSessionSec.toFixed(0)}s`,icon:bu,color:"bg-green-500"})]}),c.jsx(Ms,{title:"Traffic over time",description:`Active users, new users, sessions for ${a.property_name}`,className:"h-[400px]",children:c.jsx(T6,{series:a.traffic})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Top pages"}),c.jsx(A6,{pages:a.top_pages})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Platforms"}),c.jsx(M6,{platforms:a.platforms})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Geography"}),c.jsx(L6,{rows:a.geography})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Top events"}),c.jsx(O6,{events:a.events})]})]})]})}const rh="https://insights.hotjar.com",F6=["info@sunbird.ai","analytics@sunbird.ai"],z6=[{name:"Heatmaps",icon:Y1,color:"bg-orange-500",description:"Aggregate click, move, scroll, and rage-click maps overlaid on each page. Shows where visitors focus attention and where they drop off.",useFor:"Spot unclicked CTAs, dead zones, and content that never gets scrolled into view."},{name:"Session Recordings",icon:vR,color:"bg-red-500",description:"Replay real user sessions with cursor movement, clicks, taps, scrolls, and form interactions. Filter by country, device, page, rage click, or u-turn.",useFor:"Debug confusing UX, watch how real users navigate sign-up, and confirm a bug is reproducible in the wild."},{name:"Funnels",icon:dR,color:"bg-purple-500",description:"Multi-step conversion funnels defined by URL patterns or events. Drop-off rate is shown per step with linked recordings for each stage.",useFor:"Measure landing-page → register → first API call conversion, and watch recordings of users who dropped off."},{name:"Surveys",icon:hf,color:"bg-blue-500",description:"On-site and link surveys (NPS, CSAT, CES, exit-intent, custom). Trigger on URL, time on page, scroll depth, or exit intent.",useFor:'Ask "What were you hoping to find?" on pages with high bounce, or NPS on the dashboard.'},{name:"Feedback Widget",icon:CR,color:"bg-green-500",description:"Inline rating widget (0–5 stars / emoji) pinned to any page. Visitors pick a rating, leave a comment, and optionally highlight the exact element they are commenting on.",useFor:"Passive, continuous sentiment signal per page. Great for the pricing and docs pages."},{name:"Trends & Dashboards",icon:Q1,color:"bg-indigo-500",description:"Aggregate trends over time: page-level NPS, CSAT, feedback score, rage clicks, u-turns, conversion rate. Composable dashboards.",useFor:"Track whether the last release moved the needle on rage-clicks or feedback scores."},{name:"User Attributes",icon:PR,color:"bg-teal-500",description:"Custom identifiers (user_id, plan, organization, role) sent via the Hotjar JS SDK and used to filter and segment every other tool.",useFor:'Filter recordings to "admin users on the Speech product who hit an error" without leaking PII.'},{name:"Engage (Interviews)",icon:ek,color:"bg-pink-500",description:"Schedule moderated user interviews with calendar integration and automatic incentive delivery. Recruit from the existing visitor pool.",useFor:"Book a live session with a real user who just rage-clicked the upload flow."},{name:"Integrations",icon:AR,color:"bg-amber-500",description:"Native integrations with Slack, Jira, Linear, Microsoft Teams, Google Analytics, Segment, HubSpot, Zapier, and more.",useFor:"Pipe new survey responses into the #product Slack channel, or link a recording to a Jira ticket."}];function V6(){return c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Website & Engagement Funnel"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Qualitative website insights for all Sunbird products, powered by Hotjar."})]}),c.jsxs("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium shadow-sm",children:["Open Hotjar Insights",c.jsx(mr,{size:16})]})]}),c.jsxs("div",{className:"flex items-start gap-3 p-4 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800/40 text-amber-900 dark:text-amber-100 text-sm",children:[c.jsx(sg,{size:18,className:"flex-shrink-0 mt-0.5"}),c.jsxs("div",{children:[c.jsx("p",{className:"font-medium",children:"Why open Hotjar instead of viewing the data here?"}),c.jsx("p",{className:"mt-1 text-amber-800 dark:text-amber-200/90",children:"Hotjar's public API only exposes a limited subset of administrative data (users, sites, survey metadata). Heatmaps, recordings, funnel drop-offs, and survey responses are only viewable inside the Hotjar dashboard. We therefore link out rather than maintain a partial mirror that would miss the highest-value insights."})]})]}),c.jsx(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"bg-white dark:bg-secondary rounded-xl shadow-sm border border-gray-100 dark:border-white/5 p-6",children:c.jsxs("div",{className:"flex items-start gap-3",children:[c.jsx("div",{className:"p-2 rounded-lg bg-primary-500 bg-opacity-10 dark:bg-opacity-20",children:c.jsx(Qn,{className:"w-5 h-5 text-primary-600 dark:text-primary-400"})}),c.jsxs("div",{className:"flex-1",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"How to sign in"}),c.jsxs("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:["Hotjar access is tied to two shared Sunbird Google accounts. Use",c.jsx("span",{className:"font-medium",children:" Sign in with Google"})," — do not sign up with a new email."]}),c.jsxs("ol",{className:"mt-4 space-y-3 text-sm text-gray-700 dark:text-gray-300",children:[c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"1"}),c.jsxs("span",{children:["Open"," ",c.jsx("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"text-primary-600 dark:text-primary-400 hover:underline font-medium",children:"insights.hotjar.com"}),"."]})]}),c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"2"}),c.jsxs("span",{children:["Click ",c.jsx("span",{className:"font-medium",children:"Sign in with Google"})," and choose one of the shared accounts below."]})]}),c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"3"}),c.jsx("span",{children:"Pick the site (Sunflower, Sunbird Speech, etc.) from the organization switcher in the top-left."})]})]}),c.jsx("div",{className:"mt-5 grid grid-cols-1 sm:grid-cols-2 gap-3",children:F6.map(e=>c.jsxs("div",{className:"flex items-center gap-3 p-3 rounded-lg border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black/20",children:[c.jsx("div",{className:"p-2 rounded-md bg-primary-50 dark:bg-primary-900/30",children:c.jsx(vu,{className:"w-4 h-4 text-primary-600 dark:text-primary-400"})}),c.jsxs("div",{className:"min-w-0",children:[c.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400",children:"Shared Google account"}),c.jsx("p",{className:"text-sm font-medium text-gray-900 dark:text-white truncate",children:e})]})]},e))}),c.jsxs("p",{className:"mt-4 text-xs text-gray-500 dark:text-gray-400",children:["Credentials are managed in 1Password under ",c.jsx("em",{children:"Sunbird / Hotjar"}),". If you need access, ask an admin to add your email to the shared vault."]})]})]})}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"What you'll find in Hotjar"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"A quick guide to each tool and the kind of question it answers."}),c.jsx("div",{className:"mt-4 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",children:z6.map((e,t)=>c.jsxs(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:t*.04},className:"bg-white dark:bg-secondary p-5 rounded-xl shadow-sm border border-gray-100 dark:border-white/5 hover:border-primary-500/30 transition-colors group flex flex-col",children:[c.jsx("div",{className:`p-2 rounded-lg w-fit ${e.color} bg-opacity-10 dark:bg-opacity-20 group-hover:scale-110 transition-transform`,children:c.jsx(e.icon,{className:`w-5 h-5 ${e.color.replace("bg-","text-")}`})}),c.jsx("h3",{className:"mt-3 text-base font-semibold text-gray-900 dark:text-white",children:e.name}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-300 leading-relaxed",children:e.description}),c.jsxs("div",{className:"mt-3 pt-3 border-t border-gray-100 dark:border-white/5",children:[c.jsx("p",{className:"text-xs uppercase tracking-wide text-gray-400 dark:text-gray-500 font-medium",children:"Use it for"}),c.jsx("p",{className:"mt-1 text-xs text-gray-600 dark:text-gray-400",children:e.useFor})]})]},e.name))})]}),c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 p-5 rounded-xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black/20",children:[c.jsxs("div",{children:[c.jsx("p",{className:"text-sm font-medium text-gray-900 dark:text-white",children:"Ready to dig in?"}),c.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400 mt-1",children:"Open Hotjar in a new tab and pick the product you want to investigate."})]}),c.jsxs("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium",children:["Go to Hotjar Insights",c.jsx(mr,{size:16})]})]})]})}function Bu(){const{theme:e,setTheme:t}=B1(),{isAuthenticated:n}=Qr(),[r,s]=S.useState(!1);return c.jsxs("nav",{className:"fixed top-0 w-full z-50 bg-white/80 dark:bg-black/80 backdrop-blur-md border-b border-gray-200 dark:border-white/10",children:[c.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"flex justify-between h-16 items-center",children:[c.jsxs(Ee,{to:"/",className:"flex items-center gap-2 font-bold text-xl text-gray-900 dark:text-white",children:[c.jsx("img",{src:"/logo.png",className:"w-8 h-8 object-cover",alt:"Sunbird AI"}),c.jsx("span",{children:"Sunbird AI"})]}),c.jsxs("div",{className:"hidden md:flex items-center gap-8",children:[c.jsx("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Documentation"}),c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"GitHub"}),c.jsx("a",{href:"https://sunflower.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Sunflower"})]}),c.jsxs("div",{className:"hidden md:flex items-center gap-4",children:[c.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),className:"p-2 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 text-gray-500 dark:text-gray-400 transition-colors","aria-label":"Toggle theme",children:e==="dark"?c.jsx(pf,{size:20}):c.jsx(ff,{size:20})}),c.jsx("div",{className:"h-6 w-px bg-gray-200 dark:bg-white/10 mx-2"}),n?c.jsx(Ee,{to:"/dashboard",className:"px-4 py-2 rounded-lg bg-primary-600 hover:bg-primary-700 text-white text-sm font-medium transition-colors shadow-lg shadow-primary-500/20",children:"Dashboard"}):c.jsxs(c.Fragment,{children:[c.jsx(Ee,{to:"/login",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Log in"}),c.jsx(Ee,{to:"/register",className:"px-4 py-2 rounded-lg bg-primary-600 hover:bg-primary-700 text-white text-sm font-medium transition-colors shadow-lg shadow-primary-500/20",children:"Sign Up"})]})]}),c.jsxs("div",{className:"flex items-center gap-4 md:hidden",children:[c.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),className:"p-2 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 text-gray-500 dark:text-gray-400 transition-colors",children:e==="dark"?c.jsx(pf,{size:20}):c.jsx(ff,{size:20})}),c.jsx("button",{onClick:()=>s(!r),className:"p-2 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10",children:r?c.jsx(wu,{size:24}):c.jsx(J1,{size:24})})]})]})}),c.jsx(YT,{children:r&&c.jsx(Lo.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:"auto"},exit:{opacity:0,height:0},className:"md:hidden bg-white dark:bg-black border-b border-gray-200 dark:border-white/10 overflow-hidden",children:c.jsxs("div",{className:"px-4 pt-2 pb-6 space-y-2",children:[c.jsx("a",{href:"https://docs.sunbird.ai",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"Documentation"}),c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"GitHub"}),c.jsx("a",{href:"https://sunflower.sunbird.ai",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"Sunflower"}),c.jsx("div",{className:"pt-4 mt-4 border-t border-gray-200 dark:border-white/10",children:n?c.jsx(Ee,{to:"/dashboard",className:"block w-full text-center px-4 py-2 rounded-lg bg-primary-600 text-white font-medium",children:"Dashboard"}):c.jsxs(c.Fragment,{children:[c.jsx(Ee,{to:"/login",className:"block w-full text-center px-4 py-2 rounded-lg border border-gray-300 dark:border-white/10 text-gray-700 dark:text-gray-300 font-medium mb-3",children:"Log in"}),c.jsx(Ee,{to:"/register",className:"block w-full text-center px-4 py-2 rounded-lg bg-primary-600 text-white font-medium",children:"Sign Up"})]})})]})})})]})}function $u(){return c.jsxs("footer",{className:"border-t border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black",children:[c.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12",children:c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8",children:[c.jsxs("div",{className:"lg:col-span-2",children:[c.jsxs("div",{className:"flex items-center gap-2 font-bold text-xl text-gray-900 dark:text-white mb-4",children:[c.jsx("img",{src:"/logo.png",className:"w-8 h-8 object-cover",alt:"Sunbird AI"}),c.jsx("span",{children:"Sunbird AI"})]}),c.jsx("p",{className:"text-sm text-gray-600 dark:text-gray-400 mb-4 max-w-sm",children:"Empowering African languages with state-of-the-art AI models for translation, transcription, and speech synthesis."}),c.jsxs("div",{className:"flex gap-2",children:[c.jsx("a",{href:"https://twitter.com/sunbirdai",target:"_blank",rel:"noopener noreferrer","aria-label":"Twitter",children:c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/x-twitter.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/x-twitter.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})}),c.jsx("a",{href:"https://github.com/SunbirdAI",target:"_blank",rel:"noopener noreferrer","aria-label":"GitHub",children:c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/github.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/github.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})}),c.jsxs("a",{href:"https://www.linkedin.com/company/sunbird-ai",target:"_blank",rel:"noopener noreferrer","aria-label":"LinkedIn",children:[c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/linkedin.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/linkedin.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})," "]})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Resources"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Documentation"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"API Reference"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/translation-api-examples",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Code Examples"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api/blob/main/tutorial.md",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Tutorial"})})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Products"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://sunflower.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Sunflower"})}),c.jsx("li",{children:c.jsx(Ee,{to:"https://sunflower.sunbird.ai",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Translation"})}),c.jsx("li",{children:c.jsx(Ee,{to:"https://speech.sunbird.ai",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Speech"})})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Company"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"About Us"})}),c.jsx("li",{children:c.jsx("a",{href:"https://blog.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Blog"})}),c.jsx("li",{children:c.jsx(Ee,{to:"/privacy_policy",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Privacy Policy"})}),c.jsx("li",{children:c.jsx(Ee,{to:"/terms_of_service",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Terms of Service"})})]})]})]})}),c.jsx("div",{className:"py-5 border-t border-gray-200 dark:border-white/10 flex items-center justify-center",children:c.jsxs("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:["© ",new Date().getFullYear()," Sunbird AI. All rights reserved."]})})]})}function B6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black transition-colors duration-300 selection:bg-primary-500 selection:text-white",children:[c.jsx(Bu,{}),c.jsx("div",{className:"relative pt-32 pb-16 sm:pt-40 sm:pb-24 lg:pb-32 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto text-center overflow-hidden",children:c.jsxs(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.5},children:[c.jsxs("h1",{className:"relative text-4xl sm:text-5xl lg:text-7xl font-extrabold tracking-tight text-gray-900 dark:text-white mb-6",children:["Welcome to the ",c.jsx("br",{className:"hidden sm:block"}),c.jsx("span",{className:"text-primary-600 dark:text-primary-500",children:"Sunbird AI API"})]}),c.jsx("p",{className:"relative text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto mb-10 leading-relaxed",children:"Get started with African language AI models. Translate, transcribe, and synthesize speech with state-of-the-art models designed for the continent."}),c.jsxs("div",{className:"relative flex flex-col sm:flex-row items-center justify-center gap-4",children:[c.jsxs(Ee,{to:"/register",className:"w-full sm:w-auto px-8 py-4 rounded-xl bg-primary-600 hover:bg-primary-700 text-white font-semibold text-lg transition-all shadow-xl shadow-primary-500/20 hover:shadow-primary-500/30 flex items-center justify-center gap-2",children:["Get Started",c.jsx(df,{size:20})]}),c.jsxs("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"w-full sm:w-auto px-8 py-4 rounded-xl bg-white dark:bg-secondary hover:bg-gray-50 dark:hover:bg-white/5 border border-gray-200 dark:border-white/10 text-gray-900 dark:text-white font-semibold text-lg transition-all backdrop-blur-sm flex items-center justify-center gap-2",children:[c.jsx(Tc,{size:20}),"Read Docs"]})]})]})}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-16",children:[c.jsxs("div",{className:"text-center mb-12",children:[c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"What You Can Build"}),c.jsx("p",{className:"text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto",children:"Powerful AI capabilities for African languages at your fingertips"})]}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:[c.jsxs("a",{href:"https://docs.sunbird.ai/guides/translation",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Translate Content"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Translate text between English and 5+ local Ugandan languages with high accuracy."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/speech-to-text",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Transcribe Audio"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Convert speech audio into text for captioning, logging, or analysis."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/text-to-speech",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Generate Speech"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Turn text into natural-sounding speech in local languages."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/sunflower-chat",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Conversational AI"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Build chatbots that understand and respond in local cultural contexts."})]})]})]}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-16",children:[c.jsxs("div",{className:"text-center mb-8",children:[c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"Supported Languages"}),c.jsx("p",{className:"text-lg text-gray-600 dark:text-gray-400",children:"We support translation between English and these Ugandan languages"})]}),c.jsx("div",{className:"flex flex-wrap justify-center gap-4",children:["Luganda","Acholi","Ateso","Lugbara","Runyankole"].map(e=>c.jsx("div",{className:"px-6 py-3 rounded-full bg-white dark:bg-white/5 border border-gray-200 dark:border-white/5 text-gray-900 dark:text-white font-medium hover:border-primary-500 dark:hover:border-primary-500/50 transition-colors shadow-sm dark:shadow-md dark:shadow-black/20",children:e},e))}),c.jsx("div",{className:"text-center mt-6",children:c.jsxs("a",{href:"https://docs.sunbird.ai/languages",target:"_blank",rel:"noopener noreferrer",className:"text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300 font-medium inline-flex items-center gap-2",children:["View all supported languages",c.jsx(df,{size:16})]})})]}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-24",children:[c.jsx("div",{className:"text-center mb-12",children:c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"Get Started in Minutes"})}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6",children:[c.jsxs(Ee,{to:"/tutorial",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(Tc,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Tutorial"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Learn how to use the API with step-by-step guides and best practices."})]}),c.jsxs("a",{href:"https://github.com/SunbirdAI/translation-api-examples",target:"_blank",rel:"noopener noreferrer",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(jR,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Examples"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"View code examples and SDK usage on GitHub for Python and JS."})]}),c.jsxs(Ee,{to:"/login",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(yu,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Usage Stats"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Monitor your API usage, request volume, and limits in real-time."})]}),c.jsxs(Ee,{to:"/login",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(X1,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"API Tokens"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Manage your access tokens and security keys securely."})]})]})]}),c.jsx($u,{})]})}const $6=["NGO","Government","Private Sector","Research","Individual","Other"],Pb=["Health","Agriculture","Energy","Environment","Education","Governance"];function H6(){const[e,t]=S.useState({username:"",email:"",full_name:"",organization:"",organization_type:"",password:"",confirmPassword:""}),[n,r]=S.useState([]),[s,o]=S.useState(""),[i,a]=S.useState(""),[l,u]=S.useState(!1),[d,h]=S.useState(!1),[f,p]=S.useState(!1),g=Is(),m=async b=>{var k,w;if(b.preventDefault(),a(""),e.password!==e.confirmPassword){a("Passwords do not match");return}u(!0);try{await ae.post("/auth/register",{username:e.username,email:e.email,organization:e.organization,password:e.password,full_name:e.full_name||void 0,organization_type:e.organization_type||void 0,sector:n.length>0?n:void 0}),g("/login",{state:{message:"Registration successful! Please sign in."}})}catch(j){a(((w=(k=j.response)==null?void 0:k.data)==null?void 0:w.detail)||"Registration failed. Please try again.")}finally{u(!1)}},y=b=>{r(k=>k.includes(b)?k.filter(w=>w!==b):[...k,b])},x=()=>{const b=s.trim();b&&!n.includes(b)&&(r(k=>[...k,b]),o(""))},v=()=>{window.location.href="/auth/google/login?next=/dashboard"};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4 py-12",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Sign Up"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Sign up to access your API dashboard"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[i&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:i}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e.username,onChange:b=>t({...e,username:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"johndoe",disabled:l})]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Full Name ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(optional)"})]}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",value:e.full_name,onChange:b=>t({...e,full_name:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"John Doe",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"email",required:!0,value:e.email,onChange:b=>t({...e,email:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"you@example.com",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization"}),c.jsxs("div",{className:"relative",children:[c.jsx(H1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e.organization,onChange:b=>t({...e,organization:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Company Name",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("div",{className:"relative",children:[c.jsx($1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsxs("select",{required:!0,value:e.organization_type,onChange:b=>t({...e,organization_type:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:l,children:[c.jsx("option",{value:"",children:"Select type..."}),$6.map(b=>c.jsx("option",{value:b,children:b},b))]})]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Impact Sectors ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(select all that apply)"})]}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:[...Pb,...n.filter(b=>!Pb.includes(b))].map(b=>c.jsxs("button",{type:"button",onClick:()=>y(b),disabled:l,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${n.includes(b)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[b," ",n.includes(b)&&"✓"]},b))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:s,onChange:b=>o(b.target.value),onKeyDown:b=>b.key==="Enter"&&(b.preventDefault(),x()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:l}),c.jsx("button",{type:"button",onClick:x,disabled:l,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:d?"text":"password",required:!0,value:e.password,onChange:b=>t({...e,password:b.target.value}),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>h(!d),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:d?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:f?"text":"password",required:!0,value:e.confirmPassword,onChange:b=>t({...e,confirmPassword:b.target.value}),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>p(!f),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:f?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("button",{type:"submit",disabled:l,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors shadow-lg shadow-primary-500/20 disabled:opacity-50 disabled:cursor-not-allowed",children:[" ",l&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),l?"Creating Account...":"Create Account"]})]}),c.jsxs("div",{className:"mt-6",children:[c.jsx("div",{className:"relative",children:c.jsxs("div",{className:"relative flex justify-center items-center text-sm",children:[c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"}),c.jsx("span",{className:"px-2 text-gray-500",children:"OR"}),c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"})]})}),c.jsx("div",{className:"mt-6",children:c.jsxs("button",{onClick:v,type:"button",className:"w-full inline-flex justify-center items-center gap-2 py-2 px-4 border border-gray-300 dark:border-white/10 rounded-lg shadow-sm bg-white dark:bg-white/5 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/10 transition-colors",children:[c.jsxs("svg",{className:"w-5 h-5",xmlns:"http://www.w3.org/2000/svg",x:"0px",y:"0px",width:"25",height:"25",viewBox:"0 0 48 48",children:[c.jsx("path",{fill:"#FFC107",d:"M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"}),c.jsx("path",{fill:"#FF3D00",d:"M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"}),c.jsx("path",{fill:"#4CAF50",d:"M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"}),c.jsx("path",{fill:"#1976D2",d:"M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"})]}),"Sign Up with Google"]})})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs("p",{className:"text-sm text-gray-600 dark:text-gray-400",children:["Already have an account?"," ",c.jsx(Ee,{to:"/login",className:"font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Sign in"})]})})]})})})}function Rb(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(!1),[i,a]=S.useState(""),[l,u]=S.useState(!1),{login:d,checkAuth:h}=Qr(),f=Is(),p=ir();S.useEffect(()=>{const y=new URLSearchParams(p.search),x=y.get("token"),v=y.get("error");if(x){localStorage.setItem("access_token",x),ae.defaults.headers.common.Authorization=`Bearer ${x}`;const b=y.get("next")||"/dashboard";h().then(()=>{f(b)})}v&&a("Authentication failed. Please try again.")},[p,h,f]);const g=async y=>{var x,v;y.preventDefault(),a(""),u(!0);try{await d(e,n),f("/dashboard")}catch(b){a(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Invalid username or password")}finally{u(!1)}},m=()=>{window.location.href="/auth/google/login?next=/dashboard"};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsxs("div",{className:"max-w-md w-full space-y-8",children:[c.jsx("div",{className:"text-center"}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Sign In"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Login to access your API dashboard"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:g,children:[i&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:i}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(RR,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e,onChange:y=>t(y.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"username",disabled:l})]})]}),c.jsxs("div",{children:[c.jsxs("div",{className:"flex items-center justify-between mb-1",children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300",children:"Password"}),c.jsx(Ee,{to:"/forgot-password",className:"text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Forgot password?"})]}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:s?"text":"password",required:!0,value:n,onChange:y=>r(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>o(!s),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:s?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("button",{type:"submit",disabled:l,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:[l&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),l?"Signing in...":"Sign in"]})]}),c.jsxs("div",{className:"mt-6",children:[c.jsx("div",{className:"relative",children:c.jsxs("div",{className:"relative flex justify-center items-center text-sm",children:[c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"}),c.jsx("span",{className:"px-2 text-gray-500",children:"OR"}),c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"})]})}),c.jsx("div",{className:"mt-6",children:c.jsxs("button",{onClick:m,type:"button",className:"w-full inline-flex justify-center items-center gap-2 py-2 px-4 border border-gray-300 dark:border-white/10 rounded-lg shadow-sm bg-white dark:bg-white/5 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/10 transition-colors",children:[c.jsxs("svg",{className:"w-5 h-5",xmlns:"http://www.w3.org/2000/svg",x:"0px",y:"0px",width:"25",height:"25",viewBox:"0 0 48 48",children:[c.jsx("path",{fill:"#FFC107",d:"M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"}),c.jsx("path",{fill:"#FF3D00",d:"M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"}),c.jsx("path",{fill:"#4CAF50",d:"M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"}),c.jsx("path",{fill:"#1976D2",d:"M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"})]}),"Sign in with Google"]})})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs("p",{className:"text-sm text-gray-600 dark:text-gray-400",children:["Don't have an account?"," ",c.jsx(Ee,{to:"/register",className:"font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Sign up"})]})})]})]})})}function U6(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(""),[i,a]=S.useState(!1),l=async u=>{var d,h;u.preventDefault(),o(""),r(""),a(!0);try{const f=await ae.post("/auth/forgot-password",{email:e});f.data.success?r("Password reset email sent! Please check your inbox."):o(f.data.message||"Failed to send reset email")}catch(f){o(((h=(d=f.response)==null?void 0:d.data)==null?void 0:h.detail)||"Failed to send reset email. Please try again.")}finally{a(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary p-8 rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Forgot Password "}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Enter your email address and we'll send you a link to reset your password"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:l,children:[s&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:s}),n&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:n}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"email",required:!0,value:e,onChange:u=>t(u.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"you@example.com",disabled:i})]})]}),c.jsxs("button",{type:"submit",disabled:i,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:[i&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),i?"Sending...":"Send Reset Link"]})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs(Ee,{to:"/login",className:"inline-flex items-center gap-2 text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:[c.jsx(lR,{className:"w-4 h-4"}),"Back to Sign In"]})})]})})})}function W6(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(!1),[i,a]=S.useState(!1),[l,u]=S.useState(""),[d,h]=S.useState(!1),[f]=m1(),p=Is(),g=f.get("token");S.useEffect(()=>{g||u("Invalid or missing reset token")},[g]);const m=async y=>{var x,v;if(y.preventDefault(),u(""),e!==n){u("Passwords do not match");return}if(!g){u("Invalid reset token");return}h(!0);try{await ae.post("/auth/reset-password",{token:g,new_password:e}),p("/login",{state:{message:"Password reset successful! Please sign in with your new password."}})}catch(b){u(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Failed to reset password. The link may have expired.")}finally{h(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary p-8 rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Reset Password "}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Enter your new password below"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[l&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:l}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:s?"text":"password",required:!0,value:e,onChange:y=>t(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:d||!g}),c.jsx("button",{type:"button",onClick:()=>o(!s),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:d||!g,children:s?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:i?"text":"password",required:!0,value:n,onChange:y=>r(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:d||!g}),c.jsx("button",{type:"button",onClick:()=>a(!i),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:d||!g,children:i?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsx("button",{type:"submit",disabled:d||!g,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:d?"Resetting Password...":"Reset Password"})]})]})})})}const G6=["NGO","Government","Private Sector","Research","Individual","Other"],Eb=["Health","Agriculture","Energy","Environment","Education","Governance"];function q6(){const{user:e,checkAuth:t}=Qr(),n=Is(),[r,s]=S.useState({full_name:(e==null?void 0:e.full_name)||"",organization:(e==null?void 0:e.organization)==="Unknown"?"":(e==null?void 0:e.organization)||"",organization_type:(e==null?void 0:e.organization_type)||""}),[o,i]=S.useState((e==null?void 0:e.sector)||[]),[a,l]=S.useState(""),[u,d]=S.useState(!1),[h,f]=S.useState(""),p=y=>{i(x=>x.includes(y)?x.filter(v=>v!==y):[...x,y])},g=()=>{const y=a.trim();y&&!o.includes(y)&&(i(x=>[...x,y]),l(""))},m=async y=>{var x,v;y.preventDefault(),f(""),d(!0);try{await ae.put("/auth/profile",{full_name:r.full_name||void 0,organization:r.organization||void 0,organization_type:r.organization_type||void 0,sector:o.length>0?o:void 0}),await t(),n("/dashboard")}catch(b){f(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Failed to update profile. Please try again.")}finally{d(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4 py-12",children:c.jsxs("div",{className:"max-w-md w-full space-y-8",children:[c.jsxs("div",{className:"text-center",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover mx-auto mb-3"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Complete Your Profile"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Help us understand how you're using Sunbird AI so we can serve you better."})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5",children:[c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[h&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:h}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Full Name"}),c.jsx("input",{type:"text",value:r.full_name,onChange:y=>s({...r,full_name:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"John Doe",disabled:u})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Name"}),c.jsx("input",{type:"text",value:r.organization,onChange:y=>s({...r,organization:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Sunbird AI",disabled:u})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("select",{value:r.organization_type,onChange:y=>s({...r,organization_type:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:u,children:[c.jsx("option",{value:"",children:"Select type..."}),G6.map(y=>c.jsx("option",{value:y,children:y},y))]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Impact Sectors ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(select all that apply)"})]}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:[...Eb,...o.filter(y=>!Eb.includes(y))].map(y=>c.jsxs("button",{type:"button",onClick:()=>p(y),disabled:u,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${o.includes(y)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[y," ",o.includes(y)&&"✓"]},y))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:a,onChange:y=>l(y.target.value),onKeyDown:y=>y.key==="Enter"&&(y.preventDefault(),g()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:u}),c.jsx("button",{type:"button",onClick:g,disabled:u,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("button",{type:"submit",disabled:u,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors shadow-lg shadow-primary-500/20 disabled:opacity-50 disabled:cursor-not-allowed",children:[u&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),u?"Saving...":"Save & Continue to Dashboard"]})]}),c.jsx("div",{className:"mt-4 text-center",children:c.jsx("button",{onClick:()=>n("/dashboard"),className:"text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors",children:"Skip for now →"})})]})]})})}function K6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black flex flex-col",children:[c.jsx(Bu,{}),c.jsx("main",{className:"flex-1 pt-24 pb-16 px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"max-w-4xl mx-auto",children:[c.jsx("h1",{className:"text-4xl font-bold text-gray-900 dark:text-white mb-8",children:"Privacy Policy"}),c.jsxs("div",{className:"space-y-8 text-gray-700 dark:text-gray-300",children:[c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Introduction"}),c.jsx("p",{className:"leading-relaxed",children:"Welcome to the Privacy Policy of Sunbird AI. We understand that privacy online is important to users of our services, especially when utilizing our WhatsApp translation bot. This statement governs our privacy policies with respect to the collection, use, and disclosure of personal information when using our services."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Personally Identifiable Information"}),c.jsx("p",{className:"leading-relaxed",children:"Personally Identifiable Information refers to any information that identifies or can be used to identify, contact, or locate the person to whom such information pertains, including, but not limited to, name, address, phone number, email address, IP address, location, and browser."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"What Personally Identifiable Information is collected?"}),c.jsx("p",{className:"leading-relaxed",children:"We may collect basic user profile information from all users of our services. Additional information may be collected from users of our WhatsApp translation bot, including but not limited to, the content of messages for translation purposes."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"How is Personally Identifiable Information stored?"}),c.jsx("p",{className:"leading-relaxed",children:"Personally Identifiable Information collected by Sunbird AI is securely stored and is not accessible to third parties or employees of Sunbird AI except for use as indicated above."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"What choices are available to users regarding collection, use, and distribution of the information?"}),c.jsx("p",{className:"leading-relaxed",children:"Users may opt-out of certain data collection practices as outlined in this Privacy Policy by contacting Sunbird AI."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Changes to this Privacy Policy"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI reserves the right to update or change our Privacy Policy at any time. Users will be notified of any changes by posting the new Privacy Policy on this page."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Contact Us"}),c.jsxs("p",{className:"leading-relaxed",children:["If you have any questions about this Privacy Policy, please contact us at ",c.jsx("a",{href:"mailto:info@sunbird.ai",className:"text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 underline",children:"info@sunbird.ai"})]})]})]})]})}),c.jsx($u,{})]})}function Y6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black flex flex-col",children:[c.jsx(Bu,{}),c.jsx("main",{className:"flex-1 pt-24 pb-16 px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"max-w-4xl mx-auto",children:[c.jsx("h1",{className:"text-4xl font-bold text-gray-900 dark:text-white mb-8",children:"Terms of Service"}),c.jsxs("div",{className:"space-y-8 text-gray-700 dark:text-gray-300",children:[c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Agreement"}),c.jsx("p",{className:"leading-relaxed",children:"By accessing or using the services provided by Sunbird AI, you agree to abide by these Terms of Service. These Terms apply to all visitors, users, and others who access or use our services."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Use of Services"}),c.jsx("p",{className:"leading-relaxed",children:'Our services, including the WhatsApp translation bot, are provided on an "as is" and "as available" basis. Users are solely responsible for their use of the services and any consequences thereof.'})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Intellectual Property"}),c.jsx("p",{className:"leading-relaxed",children:"All intellectual property rights associated with the services provided by Sunbird AI, including but not limited to, the WhatsApp translation bot, are owned by Sunbird AI. Users are granted a limited, non-exclusive, non-transferable license to use the services for personal or non-commercial purposes."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Limitation of Liability"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI shall not be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly, or any loss of data, use, goodwill, or other intangible losses resulting from (i) your access to or use of or inability to access or use the services; (ii) any conduct or content of any third party on the services; (iii) any content obtained from the services; or (iv) unauthorized access, use, or alteration of your transmissions or content."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Changes to Terms of Service"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI reserves the right to update or change these Terms of Service at any time. Users will be notified of any changes by posting the new Terms of Service on this page."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Contact Us"}),c.jsxs("p",{className:"leading-relaxed",children:["If you have any questions about these Terms of Service, please contact us at ",c.jsx("a",{href:"mailto:info@sunbird.ai",className:"text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 underline",children:"info@sunbird.ai"})]})]})]})]})}),c.jsx($u,{})]})}function X6(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Q6(e,t){if(e==null)return{};var n,r,s=X6(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;re.length)&&(t=e.length);for(var n=0,r=Array(t);n{const t=Object.getPrototypeOf(e);return t.prototype&&t.prototype.isReactComponent})()}function i6(e){return typeof e=="object"&&typeof e.$$typeof=="symbol"&&["react.memo","react.forward_ref"].includes(e.$$typeof.description)}function a6(e){const t={state:{},onStateChange:()=>{},renderFallbackValue:null,...e},[n]=S.useState(()=>({current:YI(t)})),[r,s]=S.useState(()=>n.current.initialState);return n.current.setOptions(o=>({...o,...e,state:{...r,...e.state},onStateChange:i=>{s(i),e.onStateChange==null||e.onStateChange(i)}})),n.current}const IS=S.forwardRef(({className:e,...t},n)=>c.jsx("div",{className:"relative w-full overflow-auto",children:c.jsx("table",{ref:n,className:ar("w-full caption-bottom text-sm",e),...t})}));IS.displayName="Table";const FS=S.forwardRef(({className:e,...t},n)=>c.jsx("thead",{ref:n,className:ar("[&_tr]:border-b dark:border-white/5",e),...t}));FS.displayName="TableHeader";const zS=S.forwardRef(({className:e,...t},n)=>c.jsx("tbody",{ref:n,className:ar("[&_tr:last-child]:border-0",e),...t}));zS.displayName="TableBody";const l6=S.forwardRef(({className:e,...t},n)=>c.jsx("tfoot",{ref:n,className:ar("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",e),...t}));l6.displayName="TableFooter";const nc=S.forwardRef(({className:e,...t},n)=>c.jsx("tr",{ref:n,className:ar("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted dark:border-white/5 dark:hover:bg-white/5",e),...t}));nc.displayName="TableRow";const VS=S.forwardRef(({className:e,...t},n)=>c.jsx("th",{ref:n,className:ar("h-12 px-4 text-left align-middle font-semibold text-xs uppercase tracking-wider text-gray-600 dark:text-gray-400 [&:has([role=checkbox])]:pr-0 bg-gray-50 dark:bg-white/5",e),...t}));VS.displayName="TableHead";const Wf=S.forwardRef(({className:e,...t},n)=>c.jsx("td",{ref:n,className:ar("p-4 align-middle [&:has([role=checkbox])]:pr-0 text-gray-900 dark:text-gray-300",e),...t}));Wf.displayName="TableCell";const c6=S.forwardRef(({className:e,...t},n)=>c.jsx("caption",{ref:n,className:ar("mt-4 text-sm text-muted-foreground",e),...t}));c6.displayName="TableCaption";function u6({columns:e,data:t,searchable:n=!0,itemsPerPage:r=10,emptyMessage:s="No results."}){var f;const[o,i]=S.useState([]),[a,l]=S.useState([]),[u,d]=S.useState(""),h=a6({data:t,columns:e,getCoreRowModel:XI(),getPaginationRowModel:n6(),onSortingChange:i,getSortedRowModel:r6(),onColumnFiltersChange:l,getFilteredRowModel:t6(),onGlobalFilterChange:d,state:{sorting:o,columnFilters:a,globalFilter:u},initialState:{pagination:{pageSize:r}}});return c.jsxs("div",{className:"space-y-4",children:[n&&c.jsxs("div",{className:"relative",children:[c.jsx(Z1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{placeholder:"Search...",value:u??"",onChange:p=>d(p.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600"})]}),c.jsx("div",{className:"rounded-md border border-gray-200 dark:border-white/10 overflow-hidden",children:c.jsxs(IS,{children:[c.jsx(FS,{children:h.getHeaderGroups().map(p=>c.jsx(nc,{children:p.headers.map(g=>c.jsx(VS,{children:g.isPlaceholder?null:Sb(g.column.columnDef.header,g.getContext())},g.id))},p.id))}),c.jsx(zS,{children:(f=h.getRowModel().rows)!=null&&f.length?h.getRowModel().rows.map(p=>c.jsx(nc,{"data-state":p.getIsSelected()&&"selected",children:p.getVisibleCells().map(g=>c.jsx(Wf,{children:Sb(g.column.columnDef.cell,g.getContext())},g.id))},p.id)):c.jsx(nc,{children:c.jsx(Wf,{colSpan:e.length,className:"h-24 text-center",children:s})})})]})}),h.getPageCount()>1&&c.jsxs("div",{className:"flex items-center justify-between space-x-2 py-4",children:[c.jsxs("div",{className:"text-sm text-gray-700 dark:text-gray-300",children:["Page ",h.getState().pagination.pageIndex+1," of ",h.getPageCount()]}),c.jsxs("div",{className:"flex items-center gap-2",children:[c.jsx("button",{className:"p-2 rounded-lg border border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",onClick:()=>h.previousPage(),disabled:!h.getCanPreviousPage(),children:c.jsx(W1,{size:16})}),c.jsx("button",{className:"p-2 rounded-lg border border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",onClick:()=>h.nextPage(),disabled:!h.getCanNextPage(),children:c.jsx(G1,{size:16})})]})]})]})}function d6(){const{user:e}=Qr(),[t,n]=S.useState([]),[r,s]=S.useState(null),[o,i]=S.useState(!0);S.useEffect(()=>{e&&(async()=>{try{const d=localStorage.getItem("access_token");d&&n([{id:"1",name:"Current API Key",key:d,status:"Active"}])}catch(d){console.error("Failed to fetch API keys:",d)}finally{i(!1)}})()},[e]);const a=(u,d)=>{navigator.clipboard.writeText(u),s(d),setTimeout(()=>s(null),2e3)},l=[{accessorKey:"name",header:"Name"},{accessorKey:"key",header:"Key",cell:({row:u})=>c.jsxs("div",{className:"flex items-center gap-2 font-mono text-gray-700 dark:text-gray-300",children:[c.jsxs("span",{className:"truncate max-w-xs",children:[u.original.key.substring(0,20),"..."]}),c.jsx("button",{onClick:()=>a(u.original.key,u.original.id),className:"p-1 hover:bg-gray-100 dark:hover:bg-white/10 rounded transition-colors",title:"Copy key",children:r===u.original.id?c.jsx(xu,{className:"w-3 h-3 text-green-500"}):c.jsx(q1,{className:"w-3 h-3"})})]})},{accessorKey:"status",header:"Status",cell:({row:u})=>c.jsx("span",{className:`px-2 py-1 rounded-full text-xs font-medium ${u.original.status==="Active"?"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400":"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400"}`,children:u.original.status})}];return o?c.jsx("div",{className:"flex items-center justify-center h-64",children:c.jsx("div",{className:"text-gray-500 dark:text-gray-400",children:"Loading API keys..."})}):c.jsxs("div",{className:"max-w-5xl mx-auto space-y-8",children:[c.jsx("div",{className:"flex items-center justify-between",children:c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"API Keys"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Manage your API keys for authentication."})]})}),c.jsx("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:c.jsx(u6,{data:t,columns:l,itemsPerPage:10,searchable:!0,emptyMessage:"No API keys found. Generate one to get started."})}),c.jsxs("div",{className:"bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4",children:[c.jsx("h3",{className:"text-sm font-medium text-blue-900 dark:text-blue-300 mb-2",children:"Using Your API Key"}),c.jsx("p",{className:"text-sm text-blue-700 dark:text-blue-400 mb-3",children:"Include your API key in the Authorization header of your requests:"}),c.jsx("code",{className:"block bg-white dark:bg-black/50 p-3 rounded text-xs font-mono text-gray-900 dark:text-gray-100 border border-blue-200 dark:border-blue-800",children:"Authorization: Bearer YOUR_API_KEY"})]})]})}const h6=["NGO","Government","Private Sector","Research","Individual","Other"],_b=["Health","Agriculture","Energy","Environment","Education","Governance"];function f6(){const{user:e}=Qr(),{theme:t,setTheme:n}=B1(),[r,s]=S.useState({username:(e==null?void 0:e.username)||"",email:(e==null?void 0:e.email)||"",full_name:(e==null?void 0:e.full_name)||"",organization:(e==null?void 0:e.organization)||"",organization_type:(e==null?void 0:e.organization_type)||""}),[o,i]=S.useState((e==null?void 0:e.sector)||[]),[a,l]=S.useState(""),[u,d]=S.useState(""),[h,f]=S.useState(""),[p,g]=S.useState(!1),[m,y]=S.useState({oldPassword:"",newPassword:"",confirmPassword:""}),[x,v]=S.useState(""),[b,k]=S.useState(""),[w,j]=S.useState(!1),[N,_]=S.useState(!1),[P,A]=S.useState(!1),[O,F]=S.useState(!1),D=E=>{i(I=>I.includes(E)?I.filter(K=>K!==E):[...I,E])},U=()=>{const E=a.trim();E&&!o.includes(E)&&(i(I=>[...I,E]),l(""))},W=async E=>{var I,K;E.preventDefault(),f(""),d(""),g(!0);try{await ae.put("/auth/profile",{full_name:r.full_name||void 0,organization:r.organization||void 0,organization_type:r.organization_type||void 0,sector:o.length>0?o:void 0}),d("Profile updated successfully!")}catch(T){f(((K=(I=T.response)==null?void 0:I.data)==null?void 0:K.detail)||"Failed to update profile.")}finally{g(!1)}},M=async E=>{var I,K;if(E.preventDefault(),v(""),k(""),m.newPassword!==m.confirmPassword){v("New passwords do not match");return}j(!0);try{const T=await ae.post("/auth/change-password",{old_password:m.oldPassword,new_password:m.newPassword});T.data.success?(k("Password changed successfully!"),y({oldPassword:"",newPassword:"",confirmPassword:""})):v(T.data.message||"Failed to change password")}catch(T){v(((K=(I=T.response)==null?void 0:I.data)==null?void 0:K.detail)||"Failed to change password")}finally{j(!1)}},H=(e==null?void 0:e.oauth_type)==="Google"||(e==null?void 0:e.oauth_type)==="GitHub",C=!H,L=!H;return c.jsxs("div",{className:"max-w-2xl mx-auto space-y-8",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Account Settings"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Manage your profile and preferences."})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Profile Information"}),c.jsxs("form",{onSubmit:W,className:"space-y-4",children:[h&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:h}),u&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:u}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.username,onChange:E=>s({...r,username:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Full Name"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.full_name,onChange:E=>s({...r,full_name:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",placeholder:"John Doe",disabled:p})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email Address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"email",value:r.email,onChange:E=>s({...r,email:E.target.value}),className:`w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white ${L?"":"opacity-50 cursor-not-allowed"}`,disabled:!L,title:L?"":"Email cannot be changed for OAuth accounts"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization"}),c.jsxs("div",{className:"relative",children:[c.jsx(H1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:r.organization,onChange:E=>s({...r,organization:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",placeholder:"Organization Name",disabled:p})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("div",{className:"relative",children:[c.jsx($1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsxs("select",{value:r.organization_type,onChange:E=>s({...r,organization_type:E.target.value}),className:"w-full pl-9 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:p,children:[c.jsx("option",{value:"",children:"Select type..."}),h6.map(E=>c.jsx("option",{value:E,children:E},E))]})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Impact Sectors"}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-1",children:[..._b,...o.filter(E=>!_b.includes(E))].map(E=>c.jsxs("button",{type:"button",onClick:()=>D(E),disabled:p,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${o.includes(E)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[E," ",o.includes(E)&&"✓"]},E))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:a,onChange:E=>l(E.target.value),onKeyDown:E=>E.key==="Enter"&&(E.preventDefault(),U()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:p}),c.jsx("button",{type:"button",onClick:U,disabled:p,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Account Type"}),c.jsxs("div",{className:"relative",children:[c.jsx(uR,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:"text",value:(e==null?void 0:e.account_type)||"Standard",readOnly:!0,className:"w-full pl-9 pr-4 py-2 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none text-gray-500 dark:text-gray-400 cursor-not-allowed"})]})]}),c.jsx("div",{className:"pt-2",children:c.jsx("button",{type:"submit",disabled:p,className:"px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:p?"Saving...":"Save Changes"})})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Appearance"}),c.jsxs("div",{className:"grid grid-cols-3 gap-4",children:[c.jsxs("button",{onClick:()=>n("light"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="light"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(pf,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"Light"})]}),c.jsxs("button",{onClick:()=>n("dark"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="dark"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(ff,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"Dark"})]}),c.jsxs("button",{onClick:()=>n("system"),className:`p-4 rounded-lg border flex flex-col items-center gap-2 transition-all ${t==="system"?"border-primary-500 bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400":"border-gray-200 dark:border-white/10 hover:bg-gray-50 dark:hover:bg-white/5 text-gray-700 dark:text-gray-300"}`,children:[c.jsx(gR,{className:"w-6 h-6"}),c.jsx("span",{className:"text-sm font-medium",children:"System"})]})]})]}),C&&c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl p-6 shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 space-y-6",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"Change Password"}),c.jsxs("form",{onSubmit:M,className:"space-y-4",children:[x&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:x}),b&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:b}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Current Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:N?"text":"password",required:!0,placeholder:"••••••••",value:m.oldPassword,onChange:E=>y({...m,oldPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>_(!N),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:N?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:P?"text":"password",placeholder:"••••••••",required:!0,value:m.newPassword,onChange:E=>y({...m,newPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>A(!P),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:P?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"}),c.jsx("input",{type:O?"text":"password",required:!0,placeholder:"••••••••",value:m.confirmPassword,onChange:E=>y({...m,confirmPassword:E.target.value}),className:"w-full pl-9 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white",disabled:w}),c.jsx("button",{type:"button",onClick:()=>F(!O),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:w,children:O?c.jsx(Dr,{className:"w-4 h-4"}):c.jsx(Ir,{className:"w-4 h-4"})})]})]}),c.jsx("div",{className:"pt-2",children:c.jsx("button",{type:"submit",disabled:w,className:"px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:w?"Changing Password...":"Change Password"})})]})]})]})}function p6({value:e,onChange:t,options:n,placeholder:r="Select...",disabled:s=!1,className:o=""}){const[i,a]=S.useState(!1),[l,u]=S.useState(""),d=S.useRef(null),h=S.useRef(null);S.useEffect(()=>{const m=y=>{d.current&&!d.current.contains(y.target)&&(a(!1),u(""))};return document.addEventListener("mousedown",m),()=>document.removeEventListener("mousedown",m)},[]),S.useEffect(()=>{i&&h.current&&h.current.focus()},[i]);const f=n.filter(m=>m.toLowerCase().includes(l.toLowerCase())),p=m=>{t(m),a(!1),u("")},g=m=>{m.stopPropagation(),t(""),u("")};return c.jsxs("div",{className:`relative ${o}`,ref:d,children:[c.jsxs("button",{type:"button",onClick:()=>!s&&a(!i),disabled:s,className:"flex items-center justify-between w-full min-w-[240px] px-3 py-2 text-sm bg-white dark:bg-secondary border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white disabled:opacity-50 disabled:cursor-not-allowed",children:[c.jsx("span",{className:e?"text-gray-900 dark:text-white":"text-gray-400 dark:text-gray-500",children:e||r}),c.jsxs("div",{className:"flex items-center gap-1 ml-2",children:[e&&c.jsx(wu,{size:14,className:"text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 cursor-pointer",onClick:g}),c.jsx(U1,{size:16,className:`text-gray-400 transition-transform ${i?"rotate-180":""}`})]})]}),i&&c.jsxs("div",{className:"absolute z-50 w-full mt-1 bg-white dark:bg-secondary border border-gray-200 dark:border-white/10 rounded-lg shadow-lg overflow-hidden",children:[c.jsx("div",{className:"p-2 border-b border-gray-200 dark:border-white/10",children:c.jsxs("div",{className:"relative",children:[c.jsx(Z1,{size:14,className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400"}),c.jsx("input",{ref:h,type:"text",value:l,onChange:m=>u(m.target.value),placeholder:"Search...",className:"w-full pl-8 pr-3 py-1.5 text-sm bg-gray-50 dark:bg-black/30 border border-gray-200 dark:border-white/10 rounded-md focus:outline-none focus:ring-1 focus:ring-primary-500 dark:text-white placeholder-gray-400"})]})}),c.jsx("div",{className:"max-h-60 overflow-y-auto",children:f.length===0?c.jsx("div",{className:"px-3 py-4 text-sm text-gray-400 text-center",children:"No results found"}):f.map(m=>c.jsx("button",{onClick:()=>p(m),className:`w-full text-left px-3 py-2 text-sm transition-colors ${m===e?"bg-primary-50 text-primary-600 dark:bg-primary-900/20 dark:text-primary-400":"text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/5"}`,children:m},m))})]})]})}const g6=[{label:"Overview",value:"overview"},{label:"By Organization",value:"organization"},{label:"By Org Type",value:"organization_type"},{label:"By Sector",value:"sector"}];function m6({view:e,onViewChange:t,filterValue:n,onFilterValueChange:r,filters:s,filtersLoading:o}){const a=s?e==="organization"?s.organizations:e==="organization_type"?s.organization_types:e==="sector"?s.sectors:[]:[],l=e!=="overview",u=()=>e==="organization"?"Organization":e==="organization_type"?"Organization Type":e==="sector"?"Sector":"";return c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center gap-3",children:[c.jsx("div",{className:"flex items-center gap-1 bg-white dark:bg-secondary rounded-lg border border-gray-200 dark:border-white/10 p-1",children:g6.map(d=>c.jsx("button",{onClick:()=>{t(d.value),r("")},className:`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${e===d.value?"bg-primary-600 text-white":"text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-white/5"}`,children:d.label},d.value))}),l&&c.jsx(p6,{value:n,onChange:r,options:a,placeholder:`Select ${u()}...`,disabled:o||a.length===0})]})}function y6(){const[e,t]=S.useState(null),[n,r]=S.useState(!0);return S.useEffect(()=>{(async()=>{var o,i,a;try{const l=await ae.get("/api/admin/analytics/filters");t(l.data)}catch(l){_n.error(((a=(i=(o=l.response)==null?void 0:o.data)==null?void 0:i.detail)==null?void 0:a.message)||"Failed to fetch filter options")}finally{r(!1)}})()},[]),{filters:e,loading:n}}function x6(e,t,n="7d"){const[r,s]=S.useState(null),[o,i]=S.useState(!0),[a,l]=S.useState(null),u=S.useCallback(async()=>{var d,h,f;i(!0),l(null);try{let p="/api/admin/analytics/";const g=new URLSearchParams({time_range:n});e==="overview"?p+="overview":e==="organization"?(p+="by-organization",g.set("organization",t)):e==="organization_type"?(p+="by-organization-type",g.set("organization_type",t)):e==="sector"&&(p+="by-sector",g.set("sector",t));const m=await ae.get(`${p}?${g.toString()}`);s(m.data)}catch(p){const g=((f=(h=(d=p.response)==null?void 0:d.data)==null?void 0:h.detail)==null?void 0:f.message)||"Failed to fetch analytics data";l(g),_n.error(g)}finally{i(!1)}},[e,t,n]);return S.useEffect(()=>{e==="overview"||t?u():(s(null),i(!1))},[e,t,n,u]),{data:r,loading:o,error:a}}function b6(){return{exportCSV:async(t,n,r)=>{try{const s=new URLSearchParams({view:t,time_range:n});t==="organization"&&r?s.set("organization",r):t==="organization_type"&&r?s.set("organization_type",r):t==="sector"&&r&&s.set("sector",r);const o=await ae.get(`/api/admin/analytics/export?${s.toString()}`,{responseType:"blob"}),i=new Blob([o.data],{type:"text/csv"}),a=window.URL.createObjectURL(i),l=document.createElement("a");l.href=a,l.download=`analytics_${t}_${n}.csv`,document.body.appendChild(l),l.click(),document.body.removeChild(l),window.URL.revokeObjectURL(a),_n.success("CSV exported successfully")}catch{_n.error("Failed to export CSV")}}}}Bs.register(Fo,zo,Cs,bn,Iu,Fu,Du,Ou);const jb=["#E6194B","#3CB44B","#4363D8","#F58231","#911EB4","#42D4F4","#F032E6","#469990","#9A6324","#800000","#808000","#000075","#000000"];function v6(){var P,A,O,F,D,U,W,M,H,C,L,E,I,K;const[e,t]=S.useState("7d"),[n,r]=S.useState("overview"),[s,o]=S.useState(""),{filters:i,loading:a}=y6(),{data:l,loading:u}=x6(n,s,e),{exportCSV:d}=b6(),h=S.useMemo(()=>{var $;const T={Total:"#6B7280"};return($=l==null?void 0:l.endpoint_chart_data)!=null&&$.datasets&&Object.keys(l.endpoint_chart_data.datasets).sort().forEach((ne,ce)=>{T[ne]=jb[ce%jb.length]}),T},[l]),[f,p]=S.useState({Total:!0});S.useEffect(()=>{var T;(T=l==null?void 0:l.endpoint_chart_data)!=null&&T.datasets&&p($=>{const G={...$};return Object.keys(l.endpoint_chart_data.datasets).forEach(ne=>{G[ne]===void 0&&(G[ne]=!0)}),G})},[l]);const g=S.useMemo(()=>{var $;const T=[{label:"Total",value:"Total",color:h.Total}];return($=l==null?void 0:l.endpoint_chart_data)!=null&&$.datasets&&Object.keys(l.endpoint_chart_data.datasets).sort().forEach(G=>{T.push({label:G.replace("/v1/",""),value:G,color:h[G]})}),T},[l,h]),m=S.useMemo(()=>Object.keys(f).filter(T=>f[T]!==!1),[f]),y=T=>{const $={};g.forEach(G=>{$[G.value]=T.includes(G.value)}),p($)},x=((P=l==null?void 0:l.endpoint_chart_data)==null?void 0:P.datasets)||{},v={labels:((A=l==null?void 0:l.endpoint_chart_data)==null?void 0:A.labels)||((O=l==null?void 0:l.chart_data)==null?void 0:O.labels)||[],datasets:[...Object.entries(x).map(([T,$])=>({label:T,data:$,borderColor:h[T]||"#6B7280",backgroundColor:"transparent",tension:.4,borderWidth:2,hidden:f[T]===!1})),{label:"Total",data:((F=l==null?void 0:l.chart_data)==null?void 0:F.data)||[],borderColor:"#6B7280",backgroundColor:"transparent",borderWidth:3,tension:.4,hidden:f.Total===!1}]},b={labels:((D=l==null?void 0:l.latency_chart)==null?void 0:D.labels)||[],datasets:[{label:"Avg Latency (ms)",data:((W=(U=l==null?void 0:l.latency_chart)==null?void 0:U.data)==null?void 0:W.map(T=>T*1e3))||[],fill:!0,backgroundColor:T=>{const G=T.chart.ctx.createLinearGradient(0,0,0,200);return G.addColorStop(0,"rgba(59, 130, 246, 0.2)"),G.addColorStop(1,"rgba(59, 130, 246, 0)"),G},borderColor:"#3b82f6",tension:.4}]},k={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{mode:"index",intersect:!1,backgroundColor:"rgba(0, 0, 0, 0.8)",titleColor:"#fff",bodyColor:"#fff",borderColor:"rgba(255, 255, 255, 0.1)",borderWidth:1,padding:10}},scales:{x:{grid:{display:!1},ticks:{color:"rgba(156, 163, 175, 0.8)"}},y:{grid:{color:"rgba(156, 163, 175, 0.1)"},ticks:{color:"rgba(156, 163, 175, 0.8)"},beginAtZero:!0}},interaction:{mode:"nearest",axis:"x",intersect:!1}},w=((M=l==null?void 0:l.usage)==null?void 0:M.reduce((T,$)=>T+$.used,0))||0,j=(C=(H=l==null?void 0:l.latency_chart)==null?void 0:H.data)!=null&&C.length?(l.latency_chart.data.reduce((T,$)=>T+$,0)/l.latency_chart.data.length*1e3).toFixed(0):"0",N=(L=l==null?void 0:l.usage)==null?void 0:L.reduce((T,$)=>$.used>((T==null?void 0:T.used)||0)?$:T,null),_=((E=i==null?void 0:i.organizations)==null?void 0:E.length)||0;return u&&!l?c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col gap-4",children:[c.jsx(ge,{className:"h-8 w-48 mb-2"}),c.jsx(ge,{className:"h-10 w-full max-w-xl"})]}),c.jsx("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[1,2,3,4].map(T=>c.jsxs("div",{className:"bg-white dark:bg-secondary p-6 rounded-xl border border-gray-200 dark:border-white/5 shadow-sm",children:[c.jsx(ge,{className:"h-8 w-8 rounded-lg mb-4"}),c.jsx(ge,{className:"h-8 w-32 mb-1"}),c.jsx(ge,{className:"h-3 w-16"})]},T))}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Admin Analytics"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Platform-wide API usage and performance analytics."})]}),c.jsxs("button",{onClick:()=>d(n,e,s),className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium",children:[c.jsx(K1,{size:16}),"Export CSV"]})]}),c.jsx(m6,{view:n,onViewChange:r,filterValue:s,onFilterValueChange:o,filters:i,filtersLoading:a}),n!=="overview"&&!s&&c.jsxs("div",{className:"text-center py-12 text-gray-500 dark:text-gray-400",children:[c.jsx(U0,{size:48,className:"mx-auto mb-4 opacity-50"}),c.jsx("p",{className:"text-lg font-medium",children:"Select a filter value above to view analytics"})]}),(n==="overview"||s)&&l&&c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Total Requests",value:w.toLocaleString(),icon:yu,color:"bg-blue-500"}),c.jsx(kt,{label:"Avg Latency",value:`${j}ms`,icon:bu,color:"bg-orange-500"}),c.jsx(kt,{label:"Most Used",value:((I=N==null?void 0:N.endpoint)==null?void 0:I.replace("/v1/",""))||"N/A",icon:og,color:"bg-purple-500"}),c.jsx(kt,{label:"Organizations",value:_,icon:U0,color:"bg-green-500"})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsx("div",{className:"lg:col-span-2",children:c.jsxs(Ms,{title:"Request Volume by Endpoint",description:"Track usage trends across all users",showTimeSelector:!0,timeRange:e,onTimeRangeChange:t,className:"h-[400px]",children:[c.jsx("div",{className:"flex flex-wrap gap-3 mb-4 pb-4 border-b border-gray-200 dark:border-white/10",children:c.jsx(S2,{label:"Select Endpoints",options:g,selected:m,onChange:y})}),c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:k,data:v})})]})}),c.jsx(Ms,{title:"Latency Trends",description:"Average response time over the selected period",showTimeSelector:!0,timeRange:e,onTimeRangeChange:t,children:c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:k,data:b})})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Endpoint Breakdown"}),c.jsx("div",{className:"space-y-3",children:(K=l==null?void 0:l.usage)==null?void 0:K.filter(T=>T.endpoint!=="unknown").sort((T,$)=>$.used-T.used).map(T=>{const $=w>0?(T.used/w*100).toFixed(1):"0";return c.jsxs("div",{className:"flex items-center justify-between",children:[c.jsxs("div",{className:"flex items-center gap-3 flex-1",children:[c.jsx("div",{className:"w-3 h-3 rounded-full flex-shrink-0",style:{backgroundColor:h[T.endpoint]||"#6B7280"}}),c.jsx("span",{className:"text-sm text-gray-700 dark:text-gray-300",children:T.endpoint.replace("/tasks/","").replace("/tasks","tasks")})]}),c.jsxs("div",{className:"flex items-center gap-4",children:[c.jsx("span",{className:"text-sm font-medium text-gray-900 dark:text-white",children:T.used.toLocaleString()}),c.jsxs("span",{className:"text-sm text-gray-500 dark:text-gray-400 w-12 text-right",children:[$,"%"]})]})]},T.endpoint)})})]})]}),(l==null?void 0:l.per_user_breakdown)&&l.per_user_breakdown.length>0&&c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md dark:shadow-lg dark:shadow-black/10 border border-gray-200 dark:border-white/5 p-6",children:[c.jsxs("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:["User Breakdown — ",l.organization]}),c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10",children:[c.jsx("th",{className:"text-left py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Username"}),c.jsx("th",{className:"text-right py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Total Requests"}),c.jsx("th",{className:"text-left py-3 px-4 font-medium text-gray-500 dark:text-gray-400",children:"Top Endpoints"})]})}),c.jsx("tbody",{children:l.per_user_breakdown.map(T=>{const $=Object.entries(T.endpoints).sort(([,G],[,ne])=>ne-G).slice(0,3);return c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-3 px-4 text-gray-900 dark:text-white font-medium",children:T.username}),c.jsx("td",{className:"py-3 px-4 text-right text-gray-900 dark:text-white",children:T.total_requests.toLocaleString()}),c.jsx("td",{className:"py-3 px-4",children:c.jsx("div",{className:"flex flex-wrap gap-1",children:$.map(([G,ne])=>c.jsxs("span",{className:"inline-flex items-center px-2 py-0.5 rounded text-xs bg-gray-100 dark:bg-white/10 text-gray-700 dark:text-gray-300",children:[G.replace("/tasks/",""),": ",ne]},G))})})]},T.username)})})]})})]})]})]})}const BS="/api/admin/analytics/billing";function $S(e,t={}){return new URLSearchParams({category:e.category,provider:e.provider,range:e.range,resolution:e.resolution,...t})}function $a(e,t,n={}){const[r,s]=S.useState(null),[o,i]=S.useState(!0),a=JSON.stringify(n),l=S.useCallback(async()=>{var u,d;i(!0);try{const h=$S(t,JSON.parse(a)),f=await ae.get(`${BS}${e}?${h.toString()}`);s(f.data)}catch(h){const f=h;_n.error(((d=(u=f.response)==null?void 0:u.data)==null?void 0:d.message)||`Failed to load ${e}`)}finally{i(!1)}},[e,t.category,t.provider,t.range,t.resolution,a]);return S.useEffect(()=>{l()},[l]),{data:r,loading:o}}const w6=e=>$a("/summary",e),k6=e=>$a("/timeseries",e,{group_by:e.groupBy||"provider"}),S6=e=>$a("/providers",e),_6=(e,t,n,r)=>$a("/table",e,{page:String(t),page_size:"50",sort:n,sort_dir:r,...e.search?{search:e.search}:{}}),j6=(e,t)=>$a("/breakdown",e,{group_by:t});function C6(){return{exportCSV:async t=>{try{const n=$S(t),r=await ae.get(`${BS}/export?${n.toString()}`,{responseType:"blob"}),s=window.URL.createObjectURL(new Blob([r.data],{type:"text/csv"})),o=document.createElement("a");o.href=s,o.download=`billing_${t.provider}_${t.resolution}.csv`,document.body.appendChild(o),o.click(),document.body.removeChild(o),window.URL.revokeObjectURL(s),_n.success("CSV exported")}catch{_n.error("Failed to export CSV")}}}}Bs.register(Fo,zo,Cs,bn,Ci,Iu,Fu,Du,Ou);const N6=[["today","Today"],["yesterday","Yesterday"],["last_7_days","Last 7 Days"],["last_30_days","Last 30 Days"],["last_90_days","Last 90 Days"],["this_month","This Month"],["last_month","Last Month"]],Cb={runpod:"#4363D8",modal:"#F58231",vastai:"#16A34A"},Nb=["#E6194B","#3CB44B","#4363D8","#F58231","#911EB4","#42D4F4","#F032E6","#469990","#9A6324","#800000"];function P6(){var D,U,W,M,H;const[e,t]=S.useState({category:"inference",provider:"all",range:"last_30_days",resolution:"day"}),[n,r]=S.useState(1),[s,o]=S.useState("cost"),[i,a]=S.useState("desc"),[l,u]=S.useState("object"),[d,h]=S.useState(""),{data:f,loading:p}=w6(e),{data:g}=k6(e),{data:m}=S6(e),{data:y}=_6(e,n,s,i),x=e.category==="cloud"?l:"object",{data:v}=j6(e,x),{exportCSV:b}=C6(),k=((v==null?void 0:v.rows)||[]).filter(C=>C.key.toLowerCase().includes(d.toLowerCase())),w=k.reduce((C,L)=>C+L.cost,0),j=C=>{t(L=>({...L,...C})),r(1)},N=C=>{s===C?a(L=>L==="asc"?"desc":"asc"):(o(C),a("desc")),r(1)},_=C=>s===C?i==="asc"?" ▲":" ▼":"",P=(g==null?void 0:g.cost_by_group)||{},A={labels:(g==null?void 0:g.labels)||[],datasets:[...Object.entries(P).map(([C,L],E)=>({label:C,data:L,borderColor:Cb[C]||Nb[E%Nb.length],backgroundColor:"transparent",borderWidth:2,tension:.4})),{label:"Total",data:(g==null?void 0:g.cost)||[],borderColor:"#6B7280",backgroundColor:"transparent",borderWidth:3,borderDash:[5,5],tension:.4}]},O={labels:(m==null?void 0:m.labels)||[],datasets:[{data:(m==null?void 0:m.cost)||[],backgroundColor:((m==null?void 0:m.labels)||[]).map(C=>Cb[C]||"#6B7280")}]},F={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!0,labels:{color:"rgba(156,163,175,0.9)"}}},scales:{x:{grid:{display:!1},ticks:{color:"rgba(156,163,175,0.8)"}},y:{grid:{color:"rgba(156,163,175,0.1)"},beginAtZero:!0,ticks:{color:"rgba(156,163,175,0.8)"}}}};return p&&!f?c.jsxs("div",{className:"space-y-6",children:[c.jsx(ge,{className:"h-8 w-64"}),c.jsx("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[1,2,3,4].map(C=>c.jsx(ge,{className:"h-28 rounded-xl"},C))}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Infrastructure Billing"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:e.category==="training"?"Vast.ai training spend, GPU hours, and per-job breakdown.":e.category==="cloud"?"AWS & GCP spend by service and usage type.":"Runpod & Modal spend, runtime, and storage analytics."})]}),c.jsxs("button",{onClick:()=>b(e),className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 text-sm font-medium",children:[c.jsx(K1,{size:16})," Export CSV"]})]}),c.jsx("div",{className:"flex gap-1 border-b border-gray-200 dark:border-white/10",children:[["inference","Inference (Runpod & Modal)",!1],["training","Training (Vast.ai)",!1],["cloud","Cloud",!1]].map(([C,L,E])=>c.jsx("button",{disabled:E,onClick:()=>{t(I=>({...I,category:C,provider:"all",groupBy:C==="cloud"?"object":void 0})),r(1)},className:"px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors "+(E?"text-gray-300 dark:text-gray-600 cursor-not-allowed border-transparent":e.category===C?"border-primary-600 text-primary-700 dark:text-primary-400":"border-transparent text-gray-500 hover:text-gray-800 dark:hover:text-gray-200"),children:L},C))}),c.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.category==="inference"&&c.jsxs("select",{value:e.provider,onChange:C=>j({provider:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:[c.jsx("option",{value:"all",children:"All Platforms"}),c.jsx("option",{value:"runpod",children:"Runpod"}),c.jsx("option",{value:"modal",children:"Modal"})]}),e.category==="cloud"&&c.jsxs("select",{value:e.provider,onChange:C=>j({provider:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:[c.jsx("option",{value:"all",children:"All Cloud"}),c.jsx("option",{value:"aws",children:"AWS"}),c.jsx("option",{value:"gcp",children:"GCP"})]}),c.jsx("select",{value:e.range,onChange:C=>j({range:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:N6.map(([C,L])=>c.jsx("option",{value:C,children:L},C))}),c.jsx("select",{value:e.resolution,onChange:C=>j({resolution:C.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:["hour","day","week","month","year"].map(C=>c.jsx("option",{value:C,children:C[0].toUpperCase()+C.slice(1)},C))})]}),(D=f==null?void 0:f.warnings)==null?void 0:D.map(C=>c.jsx("div",{className:"text-sm text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 px-4 py-2 rounded-lg",children:C},C)),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Total Spend",value:`$${((f==null?void 0:f.total_spend)||0).toFixed(2)}`,icon:W0,color:"bg-blue-500"}),c.jsx(kt,{label:"Avg Daily Spend",value:`$${((f==null?void 0:f.avg_daily_spend)||0).toFixed(2)}`,icon:W0,color:"bg-green-500"}),c.jsx(kt,{label:"GPU Hours",value:`${(((f==null?void 0:f.total_runtime_ms)||0)/36e5).toFixed(1)}h`,icon:bu,color:"bg-orange-500"}),c.jsx(kt,{label:"Avg Storage",value:`${((f==null?void 0:f.avg_storage_gb)||0).toFixed(0)} GB`,icon:fR,color:"bg-purple-500"})]}),c.jsxs("details",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-4 text-sm text-gray-600 dark:text-gray-300",children:[c.jsxs("summary",{className:"flex items-center gap-2 cursor-pointer font-medium text-gray-900 dark:text-white",children:[c.jsx(sg,{size:16})," What these numbers mean & how they're computed"]}),c.jsxs("div",{className:"mt-3 space-y-2 leading-relaxed",children:[c.jsxs("p",{children:[c.jsx("b",{children:"Total / Avg Daily Spend"})," — USD billed by the provider for the selected range and platform(s), summed across all records. Modal amounts are pre-credit (before any credits or reservations), so your invoice may be lower."]}),c.jsxs("p",{children:[c.jsx("b",{children:"GPU Hours"})," — total billed run time, from Runpod's ",c.jsx("code",{children:"timeBilledMs"}),"(worker-time across the period). Modal bills per-app cost and does not report a runtime, so this reflects Runpod only."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Avg Storage (GB)"})," — providers bill storage as ",c.jsx("b",{children:"GB-hours"})," (capacity × hours billed), so a steady 350 GB volume reports 350 × 24 = 8,400 per day. We show the time-weighted average — total GB-hours ÷ hours in the range — as actual provisioned GB. The records table and CSV show the raw per-bucket GB-hours."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Active Endpoints / Modal Apps"})," — distinct Runpod endpoints and Modal apps with billing in the range. ",c.jsx("b",{children:"Network Volumes"})," are account-level storage, not an endpoint, so they're excluded from this count (but included in spend/storage)."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Network Volumes"})," — Runpod persistent network storage cost (",c.jsx("code",{children:"/billing/networkvolumes"}),"), shown as its own row and folded into totals."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Cost Over Time"})," — per-bucket spend with a line per platform plus a dashed Total. Buckets roll up to the selected resolution (hour → year)."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Training (Vast.ai)"})," — Vast.ai bills per contract (a whole job), not per day. We spread each contract's cost and GPU-hours evenly across the days it ran so the charts and totals are smooth and correct; the Training Jobs table lists one row per contract (job/instance) with its total GPU-hours and cost. Storage is billed as cost (not GB), so it appears in spend rather than the storage figure."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Cloud — AWS"})," — AWS costs come from Cost Explorer (UnblendedCost), broken down by service and usage type. The graph shows cost per service over time; the table toggles between Service and Usage-type and is searchable. Hourly granularity is limited by AWS to the last 14 days. Cost Explorer bills per API request, so figures are cached briefly."]}),c.jsxs("p",{children:[c.jsx("b",{children:"Cloud — GCP"})," — GCP costs come from the Cloud Billing export in BigQuery, reported as net cost (list cost after credits and discounts), broken down by service and SKU (shown under Usage-type). Billing-export data can lag up to about a day, so the current day may be partial. Each refresh runs a BigQuery query, so figures are cached briefly. Use the provider filter to view AWS or GCP on their own."]}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400",children:"Scope & freshness: Runpod is scoped to the configured endpoints; Modal covers the whole workspace. Figures are cached briefly for consistency, so very recent usage settles within the cache window."})]})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsx("div",{className:"lg:col-span-2",children:c.jsx(Ms,{title:"Cost Over Time",description:"Spend per bucket across selected platforms",className:"h-[400px]",children:c.jsx("div",{className:"flex-1 min-h-0",children:c.jsx(Vo,{options:F,data:A})})})}),c.jsx(Ms,{title:"Spend by Platform",description:e.category==="cloud"?"AWS vs GCP":e.category==="training"?"Vast.ai":"Runpod vs Modal",children:c.jsx("div",{className:"flex-1 min-h-0 flex items-center justify-center",children:c.jsx(lI,{data:O,options:{responsive:!0,maintainAspectRatio:!1}})})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Highlights"}),c.jsxs("ul",{className:"text-sm text-gray-700 dark:text-gray-300 space-y-2",children:[e.category==="training"?c.jsxs("li",{children:["Active jobs/instances: ",c.jsx("b",{children:(f==null?void 0:f.active_instances)??0})]}):e.category==="cloud"?c.jsxs("li",{children:["Active services: ",c.jsx("b",{children:(f==null?void 0:f.active_services)??0})]}):c.jsxs(c.Fragment,{children:[c.jsxs("li",{children:["Active endpoints: ",c.jsx("b",{children:(f==null?void 0:f.active_endpoints)??0})]}),c.jsxs("li",{children:["Active Modal apps: ",c.jsx("b",{children:(f==null?void 0:f.active_modal_apps)??0})]})]}),c.jsxs("li",{children:["Top endpoint: ",c.jsx("b",{children:((U=f==null?void 0:f.highest_cost_endpoint)==null?void 0:U.name)??"N/A"})," ($",(((W=f==null?void 0:f.highest_cost_endpoint)==null?void 0:W.cost)??0).toFixed(2),")"]}),c.jsxs("li",{children:["Top platform: ",c.jsx("b",{children:((M=f==null?void 0:f.highest_cost_platform)==null?void 0:M.name)??"N/A"})," ($",(((H=f==null?void 0:f.highest_cost_platform)==null?void 0:H.cost)??0).toFixed(2),")"]})]})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl border border-gray-200 dark:border-white/5 p-6",children:[c.jsxs("div",{className:"flex items-center justify-between mb-4",children:[c.jsxs("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2",children:[c.jsx(SR,{size:18})," ",e.category==="cloud"?"Cloud Cost & Usage":e.category==="training"?"Training Jobs":"Billing Records"]}),e.category==="inference"&&c.jsx("input",{type:"text",placeholder:"Search object / GPU / env...",onChange:C=>j({search:C.target.value||void 0}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm"})]}),c.jsx("div",{className:"overflow-x-auto",children:e.category==="cloud"?c.jsxs("div",{children:[c.jsxs("div",{className:"flex items-center justify-between mb-3 gap-3",children:[c.jsx("div",{className:"flex gap-1",children:["object","usage_type"].map(C=>c.jsx("button",{onClick:()=>u(C),className:"px-3 py-1 rounded text-sm "+(l===C?"bg-primary-600 text-white":"bg-gray-100 dark:bg-white/10 text-gray-700 dark:text-gray-300"),children:C==="object"?"By Service":"By Usage Type"},C))}),c.jsx("input",{type:"text",value:d,placeholder:"Search service / usage type...",onChange:C=>h(C.target.value),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm"})]}),c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:l==="object"?"Service":"Usage Type"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Cost"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Share"})]})}),c.jsx("tbody",{children:k.map(C=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.key}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(2)]}),c.jsxs("td",{className:"py-2 px-3 text-right",children:[w>0?(C.cost/w*100).toFixed(1):"0.0","%"]})]},C.key))})]})]}):e.category==="training"?c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:"Job / Instance"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"GPU Hours"}),c.jsx("th",{className:"py-2 px-3 text-right",children:"Cost"})]})}),c.jsx("tbody",{children:((v==null?void 0:v.rows)||[]).map(C=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.key}),c.jsxs("td",{className:"py-2 px-3 text-right",children:[(C.runtime_ms/36e5).toFixed(1),"h"]}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(3)]})]},C.key))})]}):c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left text-gray-500 dark:text-gray-400",children:[c.jsx("th",{className:"py-2 px-3",children:"Provider"}),c.jsx("th",{className:"py-2 px-3",children:"Object"}),c.jsxs("th",{className:"py-2 px-3 cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200",onClick:()=>N("timestamp"),children:["Date",_("timestamp")]}),c.jsxs("th",{className:"py-2 px-3 text-right cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200",onClick:()=>N("cost"),children:["Cost",_("cost")]}),c.jsx("th",{className:"py-2 px-3",children:"GPU"}),c.jsx("th",{className:"py-2 px-3",children:"Env"})]})}),c.jsx("tbody",{children:((y==null?void 0:y.rows)||[]).map((C,L)=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5",children:[c.jsx("td",{className:"py-2 px-3",children:C.provider}),c.jsx("td",{className:"py-2 px-3",children:C.object_name}),c.jsx("td",{className:"py-2 px-3",children:C.timestamp.slice(0,10)}),c.jsxs("td",{className:"py-2 px-3 text-right",children:["$",C.cost.toFixed(4)]}),c.jsx("td",{className:"py-2 px-3",children:C.gpu||"-"}),c.jsx("td",{className:"py-2 px-3",children:C.environment||"-"})]},`${C.provider}-${C.object_name}-${C.timestamp}-${L}`))})]})}),e.category==="inference"&&c.jsxs("div",{className:"flex items-center justify-between mt-4 text-sm text-gray-500 dark:text-gray-400",children:[c.jsxs("span",{children:[(y==null?void 0:y.total)??0," records"]}),c.jsxs("div",{className:"flex gap-2",children:[c.jsx("button",{disabled:n<=1,onClick:()=>r(C=>C-1),className:"px-3 py-1 rounded border border-gray-200 dark:border-white/10 disabled:opacity-40",children:"Prev"}),c.jsx("button",{disabled:!y||n*y.page_size>=y.total,onClick:()=>r(C=>C+1),className:"px-3 py-1 rounded border border-gray-200 dark:border-white/10 disabled:opacity-40",children:"Next"})]})]})]})]})}const Gf="/api/admin/google-analytics";function R6(){const[e,t]=S.useState([]),[n,r]=S.useState(!0),[s,o]=S.useState(!1);return S.useEffect(()=>{let i=!1;return(async()=>{var a;try{const{data:l}=await ae.get(`${Gf}/properties`);i||t(l.properties)}catch(l){((a=l==null?void 0:l.response)==null?void 0:a.status)===503?i||o(!0):_n.error("Failed to load GA properties")}finally{i||r(!1)}})(),()=>{i=!0}},[]),{properties:e,loading:n,notConfigured:s}}function E6(e,t){const[n,r]=S.useState(null),[s,o]=S.useState(!1),[i,a]=S.useState(null),l=S.useCallback(async(u=!1)=>{var d,h;if(e){o(!0),a(null);try{const f=u?`${Gf}/refresh`:`${Gf}/overview`,{data:p}=await ae({method:u?"post":"get",url:f,params:{property_id:e,time_range:t}});r(p)}catch(f){const p=((h=(d=f==null?void 0:f.response)==null?void 0:d.data)==null?void 0:h.detail)||"Failed to load analytics";a(typeof p=="string"?p:"Failed to load analytics"),_n.error(typeof p=="string"?p:"Failed to load analytics")}finally{o(!1)}}},[e,t]);return S.useEffect(()=>{l(!1)},[l]),{data:n,loading:s,error:i,refresh:()=>l(!0)}}function T6({series:e}){const t={labels:e.labels,datasets:[{label:"Active users",data:e.active_users,borderColor:"#3b82f6",backgroundColor:"rgba(59,130,246,0.15)",tension:.4},{label:"New users",data:e.new_users,borderColor:"#10b981",backgroundColor:"rgba(16,185,129,0.1)",tension:.4},{label:"Sessions",data:e.sessions,borderColor:"#f59e0b",backgroundColor:"rgba(245,158,11,0.1)",tension:.4}]},n={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"top"}},interaction:{mode:"index",intersect:!1},scales:{y:{beginAtZero:!0,grid:{color:"rgba(156,163,175,0.1)"}},x:{grid:{display:!1}}}};return c.jsx("div",{className:"h-[300px]",children:c.jsx(Vo,{data:t,options:n})})}function A6({pages:e}){return e.length?c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Page"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Views"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Avg duration"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsxs("td",{className:"py-2 px-3",children:[c.jsx("div",{className:"font-medium text-gray-900 dark:text-white",children:t.title||t.path}),c.jsx("div",{className:"text-xs text-gray-500 dark:text-gray-400",children:t.path})]}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.views.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.users.toLocaleString()}),c.jsxs("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:[t.avg_duration.toFixed(1),"s"]})]},t.path))})]})}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No page views in this range."})}function nh({title:e,rows:t}){const n=t.reduce((r,s)=>r+s.users,0);return c.jsxs("div",{children:[c.jsx("h4",{className:"text-sm font-semibold text-gray-700 dark:text-gray-200 mb-2",children:e}),t.length===0?c.jsx("p",{className:"text-xs text-gray-500",children:"No data."}):c.jsx("ul",{className:"space-y-1",children:t.map(r=>{const s=n?(r.users/n*100).toFixed(1):"0";return c.jsxs("li",{className:"flex items-center justify-between text-sm",children:[c.jsx("span",{className:"text-gray-700 dark:text-gray-300",children:r.label}),c.jsxs("span",{className:"text-gray-900 dark:text-white font-medium",children:[r.users.toLocaleString()," ",c.jsxs("span",{className:"text-xs text-gray-500",children:["(",s,"%)"]})]})]},r.label)})})]})}function M6({platforms:e}){return c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-6",children:[c.jsx(nh,{title:"Device",rows:e.device}),c.jsx(nh,{title:"Operating system",rows:e.os}),c.jsx(nh,{title:"Browser",rows:e.browser})]})}function L6({rows:e}){return e.length?c.jsx("div",{className:"overflow-x-auto",children:c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Country"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"City"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Sessions"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-2 px-3 text-gray-900 dark:text-white",children:t.country||"—"}),c.jsx("td",{className:"py-2 px-3 text-gray-700 dark:text-gray-300",children:t.city||"—"}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.users.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:t.sessions.toLocaleString()})]},`${t.country}-${t.city}`))})]})}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No geographic data."})}function O6({events:e}){return e.length?c.jsxs("table",{className:"w-full text-sm",children:[c.jsx("thead",{children:c.jsxs("tr",{className:"border-b border-gray-200 dark:border-white/10 text-left",children:[c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400",children:"Event"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Count"}),c.jsx("th",{className:"py-2 px-3 font-medium text-gray-500 dark:text-gray-400 text-right",children:"Users"})]})}),c.jsx("tbody",{children:e.map(t=>c.jsxs("tr",{className:"border-b border-gray-100 dark:border-white/5 hover:bg-gray-50 dark:hover:bg-white/5",children:[c.jsx("td",{className:"py-2 px-3 text-gray-900 dark:text-white font-mono text-xs",children:t.name}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-900 dark:text-white",children:t.count.toLocaleString()}),c.jsx("td",{className:"py-2 px-3 text-right text-gray-700 dark:text-gray-300",children:t.users.toLocaleString()})]},t.name))})]}):c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"No events in this range."})}Bs.register(Fo,zo,Cs,bn,Iu,Fu,Du,Ou);const D6=[{label:"Last 24h",value:"24h"},{label:"Last 7 days",value:"7d"},{label:"Last 30 days",value:"30d"},{label:"Last 60 days",value:"60d"},{label:"Last 90 days",value:"90d"}];function I6(){const{properties:e,loading:t,notConfigured:n}=R6(),[r,s]=m1(),o=r.get("property")||"",i=r.get("range")||"7d";S.useEffect(()=>{!o&&e.length>0&&s({property:e[0].id,range:i},{replace:!0})},[e,o,i,s]);const{data:a,loading:l,error:u,refresh:d}=E6(o,i),h=S.useMemo(()=>{if(!a)return null;const f=g=>g.reduce((m,y)=>m+y,0),p=g=>g.length?f(g)/g.length:0;return{users:f(a.traffic.active_users),sessions:f(a.traffic.sessions),engagementRate:p(a.traffic.engagement_rate),avgSessionSec:p(a.traffic.avg_session_duration)}},[a]);return n?c.jsx("div",{className:"text-center py-12",children:c.jsxs("p",{className:"text-gray-500 dark:text-gray-400",children:["Google Analytics is not configured. See ",c.jsx("code",{children:"docs/google-analytics.md"}),"."]})}):t?c.jsxs("div",{className:"space-y-6",children:[c.jsx(ge,{className:"h-8 w-48"}),c.jsx(ge,{className:"h-10 w-full max-w-xl"}),c.jsx(ge,{className:"h-[400px] w-full rounded-xl"})]}):c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Google Analytics"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Site & app analytics for Sunbird properties."})]}),c.jsxs("button",{onClick:()=>{d(),_n.info("Refreshing from Google Analytics…")},disabled:l,className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 disabled:opacity-50 transition-colors text-sm font-medium",children:[c.jsx(kR,{size:16,className:l?"animate-spin":""}),"Refresh"]})]}),c.jsxs("div",{className:"flex flex-wrap gap-3 items-center",children:[c.jsx("select",{value:o,onChange:f=>s({property:f.target.value,range:i}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:e.map(f=>c.jsx("option",{value:f.id,children:f.name},f.id))}),c.jsx("select",{value:i,onChange:f=>s({property:o,range:f.target.value}),className:"px-3 py-2 rounded-lg border border-gray-200 dark:border-white/10 bg-white dark:bg-secondary text-sm",children:D6.map(f=>c.jsx("option",{value:f.value,children:f.label},f.value))}),a&&c.jsxs("span",{className:"text-xs text-gray-500 dark:text-gray-400 ml-auto",children:["Cached until ",new Date(a.cached_until).toLocaleTimeString()]})]}),l&&!a&&c.jsx(ge,{className:"h-[400px] w-full rounded-xl"}),u&&!a&&c.jsx("div",{className:"p-4 rounded-lg bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 text-sm",children:u}),a&&h&&c.jsxs(c.Fragment,{children:[a.partial&&c.jsxs("div",{className:"p-3 rounded-lg bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-200 text-sm",children:["Some reports failed to load: ",a.failed_reports.join(", "),"."]}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-4 gap-4",children:[c.jsx(kt,{label:"Users",value:h.users.toLocaleString(),icon:ek,color:"bg-blue-500"}),c.jsx(kt,{label:"Sessions",value:h.sessions.toLocaleString(),icon:yu,color:"bg-orange-500"}),c.jsx(kt,{label:"Engagement",value:`${(h.engagementRate*100).toFixed(1)}%`,icon:og,color:"bg-purple-500"}),c.jsx(kt,{label:"Avg session",value:`${h.avgSessionSec.toFixed(0)}s`,icon:bu,color:"bg-green-500"})]}),c.jsx(Ms,{title:"Traffic over time",description:`Active users, new users, sessions for ${a.property_name}`,className:"h-[400px]",children:c.jsx(T6,{series:a.traffic})}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Top pages"}),c.jsx(A6,{pages:a.top_pages})]}),c.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Platforms"}),c.jsx(M6,{platforms:a.platforms})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Geography"}),c.jsx(L6,{rows:a.geography})]})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-xl shadow-md border border-gray-200 dark:border-white/5 p-6",children:[c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-4",children:"Top events"}),c.jsx(O6,{events:a.events})]})]})]})}const rh="https://insights.hotjar.com",F6=["info@sunbird.ai","analytics@sunbird.ai"],z6=[{name:"Heatmaps",icon:Y1,color:"bg-orange-500",description:"Aggregate click, move, scroll, and rage-click maps overlaid on each page. Shows where visitors focus attention and where they drop off.",useFor:"Spot unclicked CTAs, dead zones, and content that never gets scrolled into view."},{name:"Session Recordings",icon:vR,color:"bg-red-500",description:"Replay real user sessions with cursor movement, clicks, taps, scrolls, and form interactions. Filter by country, device, page, rage click, or u-turn.",useFor:"Debug confusing UX, watch how real users navigate sign-up, and confirm a bug is reproducible in the wild."},{name:"Funnels",icon:dR,color:"bg-purple-500",description:"Multi-step conversion funnels defined by URL patterns or events. Drop-off rate is shown per step with linked recordings for each stage.",useFor:"Measure landing-page → register → first API call conversion, and watch recordings of users who dropped off."},{name:"Surveys",icon:hf,color:"bg-blue-500",description:"On-site and link surveys (NPS, CSAT, CES, exit-intent, custom). Trigger on URL, time on page, scroll depth, or exit intent.",useFor:'Ask "What were you hoping to find?" on pages with high bounce, or NPS on the dashboard.'},{name:"Feedback Widget",icon:CR,color:"bg-green-500",description:"Inline rating widget (0–5 stars / emoji) pinned to any page. Visitors pick a rating, leave a comment, and optionally highlight the exact element they are commenting on.",useFor:"Passive, continuous sentiment signal per page. Great for the pricing and docs pages."},{name:"Trends & Dashboards",icon:Q1,color:"bg-indigo-500",description:"Aggregate trends over time: page-level NPS, CSAT, feedback score, rage clicks, u-turns, conversion rate. Composable dashboards.",useFor:"Track whether the last release moved the needle on rage-clicks or feedback scores."},{name:"User Attributes",icon:PR,color:"bg-teal-500",description:"Custom identifiers (user_id, plan, organization, role) sent via the Hotjar JS SDK and used to filter and segment every other tool.",useFor:'Filter recordings to "admin users on the Speech product who hit an error" without leaking PII.'},{name:"Engage (Interviews)",icon:ek,color:"bg-pink-500",description:"Schedule moderated user interviews with calendar integration and automatic incentive delivery. Recruit from the existing visitor pool.",useFor:"Book a live session with a real user who just rage-clicked the upload flow."},{name:"Integrations",icon:AR,color:"bg-amber-500",description:"Native integrations with Slack, Jira, Linear, Microsoft Teams, Google Analytics, Segment, HubSpot, Zapier, and more.",useFor:"Pipe new survey responses into the #product Slack channel, or link a recording to a Jira ticket."}];function V6(){return c.jsxs("div",{className:"space-y-6",children:[c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[c.jsxs("div",{children:[c.jsx("h1",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Website & Engagement Funnel"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"Qualitative website insights for all Sunbird products, powered by Hotjar."})]}),c.jsxs("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium shadow-sm",children:["Open Hotjar Insights",c.jsx(mr,{size:16})]})]}),c.jsxs("div",{className:"flex items-start gap-3 p-4 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800/40 text-amber-900 dark:text-amber-100 text-sm",children:[c.jsx(sg,{size:18,className:"flex-shrink-0 mt-0.5"}),c.jsxs("div",{children:[c.jsx("p",{className:"font-medium",children:"Why open Hotjar instead of viewing the data here?"}),c.jsx("p",{className:"mt-1 text-amber-800 dark:text-amber-200/90",children:"Hotjar's public API only exposes a limited subset of administrative data (users, sites, survey metadata). Heatmaps, recordings, funnel drop-offs, and survey responses are only viewable inside the Hotjar dashboard. We therefore link out rather than maintain a partial mirror that would miss the highest-value insights."})]})]}),c.jsx(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"bg-white dark:bg-secondary rounded-xl shadow-sm border border-gray-100 dark:border-white/5 p-6",children:c.jsxs("div",{className:"flex items-start gap-3",children:[c.jsx("div",{className:"p-2 rounded-lg bg-primary-500 bg-opacity-10 dark:bg-opacity-20",children:c.jsx(Qn,{className:"w-5 h-5 text-primary-600 dark:text-primary-400"})}),c.jsxs("div",{className:"flex-1",children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"How to sign in"}),c.jsxs("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:["Hotjar access is tied to two shared Sunbird Google accounts. Use",c.jsx("span",{className:"font-medium",children:" Sign in with Google"})," — do not sign up with a new email."]}),c.jsxs("ol",{className:"mt-4 space-y-3 text-sm text-gray-700 dark:text-gray-300",children:[c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"1"}),c.jsxs("span",{children:["Open"," ",c.jsx("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"text-primary-600 dark:text-primary-400 hover:underline font-medium",children:"insights.hotjar.com"}),"."]})]}),c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"2"}),c.jsxs("span",{children:["Click ",c.jsx("span",{className:"font-medium",children:"Sign in with Google"})," and choose one of the shared accounts below."]})]}),c.jsxs("li",{className:"flex gap-3",children:[c.jsx("span",{className:"flex-shrink-0 w-6 h-6 rounded-full bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 flex items-center justify-center text-xs font-semibold",children:"3"}),c.jsx("span",{children:"Pick the site (Sunflower, Sunbird Speech, etc.) from the organization switcher in the top-left."})]})]}),c.jsx("div",{className:"mt-5 grid grid-cols-1 sm:grid-cols-2 gap-3",children:F6.map(e=>c.jsxs("div",{className:"flex items-center gap-3 p-3 rounded-lg border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black/20",children:[c.jsx("div",{className:"p-2 rounded-md bg-primary-50 dark:bg-primary-900/30",children:c.jsx(vu,{className:"w-4 h-4 text-primary-600 dark:text-primary-400"})}),c.jsxs("div",{className:"min-w-0",children:[c.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400",children:"Shared Google account"}),c.jsx("p",{className:"text-sm font-medium text-gray-900 dark:text-white truncate",children:e})]})]},e))}),c.jsxs("p",{className:"mt-4 text-xs text-gray-500 dark:text-gray-400",children:["Credentials are managed in 1Password under ",c.jsx("em",{children:"Sunbird / Hotjar"}),". If you need access, ask an admin to add your email to the shared vault."]})]})]})}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-lg font-semibold text-gray-900 dark:text-white",children:"What you'll find in Hotjar"}),c.jsx("p",{className:"text-sm text-gray-500 dark:text-gray-400 mt-1",children:"A quick guide to each tool and the kind of question it answers."}),c.jsx("div",{className:"mt-4 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",children:z6.map((e,t)=>c.jsxs(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:t*.04},className:"bg-white dark:bg-secondary p-5 rounded-xl shadow-sm border border-gray-100 dark:border-white/5 hover:border-primary-500/30 transition-colors group flex flex-col",children:[c.jsx("div",{className:`p-2 rounded-lg w-fit ${e.color} bg-opacity-10 dark:bg-opacity-20 group-hover:scale-110 transition-transform`,children:c.jsx(e.icon,{className:`w-5 h-5 ${e.color.replace("bg-","text-")}`})}),c.jsx("h3",{className:"mt-3 text-base font-semibold text-gray-900 dark:text-white",children:e.name}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-300 leading-relaxed",children:e.description}),c.jsxs("div",{className:"mt-3 pt-3 border-t border-gray-100 dark:border-white/5",children:[c.jsx("p",{className:"text-xs uppercase tracking-wide text-gray-400 dark:text-gray-500 font-medium",children:"Use it for"}),c.jsx("p",{className:"mt-1 text-xs text-gray-600 dark:text-gray-400",children:e.useFor})]})]},e.name))})]}),c.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 p-5 rounded-xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black/20",children:[c.jsxs("div",{children:[c.jsx("p",{className:"text-sm font-medium text-gray-900 dark:text-white",children:"Ready to dig in?"}),c.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400 mt-1",children:"Open Hotjar in a new tab and pick the product you want to investigate."})]}),c.jsxs("a",{href:rh,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm font-medium",children:["Go to Hotjar Insights",c.jsx(mr,{size:16})]})]})]})}function Bu(){const{theme:e,setTheme:t}=B1(),{isAuthenticated:n}=Qr(),[r,s]=S.useState(!1);return c.jsxs("nav",{className:"fixed top-0 w-full z-50 bg-white/80 dark:bg-black/80 backdrop-blur-md border-b border-gray-200 dark:border-white/10",children:[c.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"flex justify-between h-16 items-center",children:[c.jsxs(Ee,{to:"/",className:"flex items-center gap-2 font-bold text-xl text-gray-900 dark:text-white",children:[c.jsx("img",{src:"/logo.png",className:"w-8 h-8 object-cover",alt:"Sunbird AI"}),c.jsx("span",{children:"Sunbird AI"})]}),c.jsxs("div",{className:"hidden md:flex items-center gap-8",children:[c.jsx("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Documentation"}),c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"GitHub"}),c.jsx("a",{href:"https://sunflower.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Sunflower"})]}),c.jsxs("div",{className:"hidden md:flex items-center gap-4",children:[c.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),className:"p-2 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 text-gray-500 dark:text-gray-400 transition-colors","aria-label":"Toggle theme",children:e==="dark"?c.jsx(pf,{size:20}):c.jsx(ff,{size:20})}),c.jsx("div",{className:"h-6 w-px bg-gray-200 dark:bg-white/10 mx-2"}),n?c.jsx(Ee,{to:"/dashboard",className:"px-4 py-2 rounded-lg bg-primary-600 hover:bg-primary-700 text-white text-sm font-medium transition-colors shadow-lg shadow-primary-500/20",children:"Dashboard"}):c.jsxs(c.Fragment,{children:[c.jsx(Ee,{to:"/login",className:"text-sm font-medium text-gray-700 hover:text-primary-600 dark:text-gray-300 dark:hover:text-primary-400 transition-colors",children:"Log in"}),c.jsx(Ee,{to:"/register",className:"px-4 py-2 rounded-lg bg-primary-600 hover:bg-primary-700 text-white text-sm font-medium transition-colors shadow-lg shadow-primary-500/20",children:"Sign Up"})]})]}),c.jsxs("div",{className:"flex items-center gap-4 md:hidden",children:[c.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),className:"p-2 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 text-gray-500 dark:text-gray-400 transition-colors",children:e==="dark"?c.jsx(pf,{size:20}):c.jsx(ff,{size:20})}),c.jsx("button",{onClick:()=>s(!r),className:"p-2 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10",children:r?c.jsx(wu,{size:24}):c.jsx(J1,{size:24})})]})]})}),c.jsx(YT,{children:r&&c.jsx(Lo.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:"auto"},exit:{opacity:0,height:0},className:"md:hidden bg-white dark:bg-black border-b border-gray-200 dark:border-white/10 overflow-hidden",children:c.jsxs("div",{className:"px-4 pt-2 pb-6 space-y-2",children:[c.jsx("a",{href:"https://docs.sunbird.ai",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"Documentation"}),c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"GitHub"}),c.jsx("a",{href:"https://sunflower.sunbird.ai",className:"block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5",children:"Sunflower"}),c.jsx("div",{className:"pt-4 mt-4 border-t border-gray-200 dark:border-white/10",children:n?c.jsx(Ee,{to:"/dashboard",className:"block w-full text-center px-4 py-2 rounded-lg bg-primary-600 text-white font-medium",children:"Dashboard"}):c.jsxs(c.Fragment,{children:[c.jsx(Ee,{to:"/login",className:"block w-full text-center px-4 py-2 rounded-lg border border-gray-300 dark:border-white/10 text-gray-700 dark:text-gray-300 font-medium mb-3",children:"Log in"}),c.jsx(Ee,{to:"/register",className:"block w-full text-center px-4 py-2 rounded-lg bg-primary-600 text-white font-medium",children:"Sign Up"})]})})]})})})]})}function $u(){return c.jsxs("footer",{className:"border-t border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-black",children:[c.jsx("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12",children:c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8",children:[c.jsxs("div",{className:"lg:col-span-2",children:[c.jsxs("div",{className:"flex items-center gap-2 font-bold text-xl text-gray-900 dark:text-white mb-4",children:[c.jsx("img",{src:"/logo.png",className:"w-8 h-8 object-cover",alt:"Sunbird AI"}),c.jsx("span",{children:"Sunbird AI"})]}),c.jsx("p",{className:"text-sm text-gray-600 dark:text-gray-400 mb-4 max-w-sm",children:"Empowering African languages with state-of-the-art AI models for translation, transcription, and speech synthesis."}),c.jsxs("div",{className:"flex gap-2",children:[c.jsx("a",{href:"https://twitter.com/sunbirdai",target:"_blank",rel:"noopener noreferrer","aria-label":"Twitter",children:c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/x-twitter.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/x-twitter.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})}),c.jsx("a",{href:"https://github.com/SunbirdAI",target:"_blank",rel:"noopener noreferrer","aria-label":"GitHub",children:c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/github.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/github.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})}),c.jsxs("a",{href:"https://www.linkedin.com/company/sunbird-ai",target:"_blank",rel:"noopener noreferrer","aria-label":"LinkedIn",children:[c.jsx("svg",{className:"w-5 h-5 bg-gray-400 dark:bg-gray-500 hover:bg-gray-500 dark:hover:bg-gray-400",style:{WebkitMaskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/linkedin.svg)",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",maskImage:"url(https://d3gk2c5xim1je2.cloudfront.net/v7.1.0/brands/linkedin.svg)",maskRepeat:"no-repeat",maskPosition:"center"}})," "]})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Resources"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Documentation"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"API Reference"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/translation-api-examples",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Code Examples"})}),c.jsx("li",{children:c.jsx("a",{href:"https://github.com/SunbirdAI/sunbird-ai-api/blob/main/tutorial.md",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Tutorial"})})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Products"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://sunflower.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Sunflower"})}),c.jsx("li",{children:c.jsx(Ee,{to:"https://sunflower.sunbird.ai",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Translation"})}),c.jsx("li",{children:c.jsx(Ee,{to:"https://speech.sunbird.ai",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Speech"})})]})]}),c.jsxs("div",{children:[c.jsx("h3",{className:"font-semibold text-gray-900 dark:text-white mb-4",children:"Company"}),c.jsxs("ul",{className:"space-y-3",children:[c.jsx("li",{children:c.jsx("a",{href:"https://sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"About Us"})}),c.jsx("li",{children:c.jsx("a",{href:"https://blog.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Blog"})}),c.jsx("li",{children:c.jsx(Ee,{to:"/privacy_policy",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Privacy Policy"})}),c.jsx("li",{children:c.jsx(Ee,{to:"/terms_of_service",className:"text-sm text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors",children:"Terms of Service"})})]})]})]})}),c.jsx("div",{className:"py-5 border-t border-gray-200 dark:border-white/10 flex items-center justify-center",children:c.jsxs("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:["© ",new Date().getFullYear()," Sunbird AI. All rights reserved."]})})]})}function B6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black transition-colors duration-300 selection:bg-primary-500 selection:text-white",children:[c.jsx(Bu,{}),c.jsx("div",{className:"relative pt-32 pb-16 sm:pt-40 sm:pb-24 lg:pb-32 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto text-center overflow-hidden",children:c.jsxs(Lo.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.5},children:[c.jsxs("h1",{className:"relative text-4xl sm:text-5xl lg:text-7xl font-extrabold tracking-tight text-gray-900 dark:text-white mb-6",children:["Welcome to the ",c.jsx("br",{className:"hidden sm:block"}),c.jsx("span",{className:"text-primary-600 dark:text-primary-500",children:"Sunbird AI API"})]}),c.jsx("p",{className:"relative text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto mb-10 leading-relaxed",children:"Get started with African language AI models. Translate, transcribe, and synthesize speech with state-of-the-art models designed for the continent."}),c.jsxs("div",{className:"relative flex flex-col sm:flex-row items-center justify-center gap-4",children:[c.jsxs(Ee,{to:"/register",className:"w-full sm:w-auto px-8 py-4 rounded-xl bg-primary-600 hover:bg-primary-700 text-white font-semibold text-lg transition-all shadow-xl shadow-primary-500/20 hover:shadow-primary-500/30 flex items-center justify-center gap-2",children:["Get Started",c.jsx(df,{size:20})]}),c.jsxs("a",{href:"https://docs.sunbird.ai",target:"_blank",rel:"noopener noreferrer",className:"w-full sm:w-auto px-8 py-4 rounded-xl bg-white dark:bg-secondary hover:bg-gray-50 dark:hover:bg-white/5 border border-gray-200 dark:border-white/10 text-gray-900 dark:text-white font-semibold text-lg transition-all backdrop-blur-sm flex items-center justify-center gap-2",children:[c.jsx(Tc,{size:20}),"Read Docs"]})]})]})}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-16",children:[c.jsxs("div",{className:"text-center mb-12",children:[c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"What You Can Build"}),c.jsx("p",{className:"text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto",children:"Powerful AI capabilities for African languages at your fingertips"})]}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:[c.jsxs("a",{href:"https://docs.sunbird.ai/guides/translation",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Translate Content"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Translate text between English and 5+ local Ugandan languages with high accuracy."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/speech-to-text",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Transcribe Audio"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Convert speech audio into text for captioning, logging, or analysis."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/text-to-speech",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Generate Speech"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Turn text into natural-sounding speech in local languages."})]}),c.jsxs("a",{href:"https://docs.sunbird.ai/guides/sunflower-chat",target:"_blank",rel:"noopener noreferrer",className:"group p-8 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1",children:[c.jsx("div",{className:"w-14 h-14 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx("svg",{className:"w-7 h-7",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"})})}),c.jsx("h3",{className:"text-xl font-semibold text-gray-900 dark:text-white mb-2",children:"Conversational AI"}),c.jsx("p",{className:"text-gray-600 dark:text-gray-400",children:"Build chatbots that understand and respond in local cultural contexts."})]})]})]}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-16",children:[c.jsxs("div",{className:"text-center mb-8",children:[c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"Supported Languages"}),c.jsx("p",{className:"text-lg text-gray-600 dark:text-gray-400",children:"We support translation between English and these Ugandan languages"})]}),c.jsx("div",{className:"flex flex-wrap justify-center gap-4",children:["Luganda","Acholi","Ateso","Lugbara","Runyankole"].map(e=>c.jsx("div",{className:"px-6 py-3 rounded-full bg-white dark:bg-white/5 border border-gray-200 dark:border-white/5 text-gray-900 dark:text-white font-medium hover:border-primary-500 dark:hover:border-primary-500/50 transition-colors shadow-sm dark:shadow-md dark:shadow-black/20",children:e},e))}),c.jsx("div",{className:"text-center mt-6",children:c.jsxs("a",{href:"https://docs.sunbird.ai/languages",target:"_blank",rel:"noopener noreferrer",className:"text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300 font-medium inline-flex items-center gap-2",children:["View all supported languages",c.jsx(df,{size:16})]})})]}),c.jsxs("div",{className:"px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto pb-24",children:[c.jsx("div",{className:"text-center mb-12",children:c.jsx("h2",{className:"text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4",children:"Get Started in Minutes"})}),c.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6",children:[c.jsxs(Ee,{to:"/tutorial",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(Tc,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Tutorial"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Learn how to use the API with step-by-step guides and best practices."})]}),c.jsxs("a",{href:"https://github.com/SunbirdAI/translation-api-examples",target:"_blank",rel:"noopener noreferrer",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(jR,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Examples"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"View code examples and SDK usage on GitHub for Python and JS."})]}),c.jsxs(Ee,{to:"/login",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(yu,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"Usage Stats"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Monitor your API usage, request volume, and limits in real-time."})]}),c.jsxs(Ee,{to:"/login",className:"group p-6 rounded-2xl bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 border-b-4 hover:border-primary-500 dark:hover:border-primary-500 transition-all hover:shadow-2xl hover:-translate-y-1 backdrop-blur-sm",children:[c.jsx("div",{className:"w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-900/20 flex items-center justify-center text-primary-600 dark:text-primary-400 mb-4 group-hover:scale-110 transition-transform",children:c.jsx(X1,{size:24})}),c.jsx("h3",{className:"text-lg font-semibold text-gray-900 dark:text-white mb-2",children:"API Tokens"}),c.jsx("p",{className:"text-gray-500 dark:text-gray-400 text-sm leading-relaxed",children:"Manage your access tokens and security keys securely."})]})]})]}),c.jsx($u,{})]})}const $6=["NGO","Government","Private Sector","Research","Individual","Other"],Pb=["Health","Agriculture","Energy","Environment","Education","Governance"];function H6(){const[e,t]=S.useState({username:"",email:"",full_name:"",organization:"",organization_type:"",password:"",confirmPassword:""}),[n,r]=S.useState([]),[s,o]=S.useState(""),[i,a]=S.useState(""),[l,u]=S.useState(!1),[d,h]=S.useState(!1),[f,p]=S.useState(!1),g=Is(),m=async b=>{var k,w;if(b.preventDefault(),a(""),e.password!==e.confirmPassword){a("Passwords do not match");return}u(!0);try{await ae.post("/auth/register",{username:e.username,email:e.email,organization:e.organization,password:e.password,full_name:e.full_name||void 0,organization_type:e.organization_type||void 0,sector:n.length>0?n:void 0}),g("/login",{state:{message:"Registration successful! Please sign in."}})}catch(j){a(((w=(k=j.response)==null?void 0:k.data)==null?void 0:w.detail)||"Registration failed. Please try again.")}finally{u(!1)}},y=b=>{r(k=>k.includes(b)?k.filter(w=>w!==b):[...k,b])},x=()=>{const b=s.trim();b&&!n.includes(b)&&(r(k=>[...k,b]),o(""))},v=()=>{window.location.href="/auth/google/login?next=/dashboard"};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4 py-12",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Sign Up"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Sign up to access your API dashboard"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[i&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:i}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e.username,onChange:b=>t({...e,username:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"johndoe",disabled:l})]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Full Name ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(optional)"})]}),c.jsxs("div",{className:"relative",children:[c.jsx(To,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",value:e.full_name,onChange:b=>t({...e,full_name:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"John Doe",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"email",required:!0,value:e.email,onChange:b=>t({...e,email:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"you@example.com",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization"}),c.jsxs("div",{className:"relative",children:[c.jsx(H1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e.organization,onChange:b=>t({...e,organization:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Company Name",disabled:l})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("div",{className:"relative",children:[c.jsx($1,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsxs("select",{required:!0,value:e.organization_type,onChange:b=>t({...e,organization_type:b.target.value}),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:l,children:[c.jsx("option",{value:"",children:"Select type..."}),$6.map(b=>c.jsx("option",{value:b,children:b},b))]})]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Impact Sectors ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(select all that apply)"})]}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:[...Pb,...n.filter(b=>!Pb.includes(b))].map(b=>c.jsxs("button",{type:"button",onClick:()=>y(b),disabled:l,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${n.includes(b)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[b," ",n.includes(b)&&"✓"]},b))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:s,onChange:b=>o(b.target.value),onKeyDown:b=>b.key==="Enter"&&(b.preventDefault(),x()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:l}),c.jsx("button",{type:"button",onClick:x,disabled:l,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:d?"text":"password",required:!0,value:e.password,onChange:b=>t({...e,password:b.target.value}),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>h(!d),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:d?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:f?"text":"password",required:!0,value:e.confirmPassword,onChange:b=>t({...e,confirmPassword:b.target.value}),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>p(!f),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:f?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("button",{type:"submit",disabled:l,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors shadow-lg shadow-primary-500/20 disabled:opacity-50 disabled:cursor-not-allowed",children:[" ",l&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),l?"Creating Account...":"Create Account"]})]}),c.jsxs("div",{className:"mt-6",children:[c.jsx("div",{className:"relative",children:c.jsxs("div",{className:"relative flex justify-center items-center text-sm",children:[c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"}),c.jsx("span",{className:"px-2 text-gray-500",children:"OR"}),c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"})]})}),c.jsx("div",{className:"mt-6",children:c.jsxs("button",{onClick:v,type:"button",className:"w-full inline-flex justify-center items-center gap-2 py-2 px-4 border border-gray-300 dark:border-white/10 rounded-lg shadow-sm bg-white dark:bg-white/5 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/10 transition-colors",children:[c.jsxs("svg",{className:"w-5 h-5",xmlns:"http://www.w3.org/2000/svg",x:"0px",y:"0px",width:"25",height:"25",viewBox:"0 0 48 48",children:[c.jsx("path",{fill:"#FFC107",d:"M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"}),c.jsx("path",{fill:"#FF3D00",d:"M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"}),c.jsx("path",{fill:"#4CAF50",d:"M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"}),c.jsx("path",{fill:"#1976D2",d:"M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"})]}),"Sign Up with Google"]})})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs("p",{className:"text-sm text-gray-600 dark:text-gray-400",children:["Already have an account?"," ",c.jsx(Ee,{to:"/login",className:"font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Sign in"})]})})]})})})}function Rb(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(!1),[i,a]=S.useState(""),[l,u]=S.useState(!1),{login:d,checkAuth:h}=Qr(),f=Is(),p=ir();S.useEffect(()=>{const y=new URLSearchParams(p.search),x=y.get("token"),v=y.get("error");if(x){localStorage.setItem("access_token",x),ae.defaults.headers.common.Authorization=`Bearer ${x}`;const b=y.get("next")||"/dashboard";h().then(()=>{f(b)})}v&&a("Authentication failed. Please try again.")},[p,h,f]);const g=async y=>{var x,v;y.preventDefault(),a(""),u(!0);try{await d(e,n),f("/dashboard")}catch(b){a(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Invalid username or password")}finally{u(!1)}},m=()=>{window.location.href="/auth/google/login?next=/dashboard"};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsxs("div",{className:"max-w-md w-full space-y-8",children:[c.jsx("div",{className:"text-center"}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Sign In"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Login to access your API dashboard"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:g,children:[i&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:i}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Username"}),c.jsxs("div",{className:"relative",children:[c.jsx(RR,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"text",required:!0,value:e,onChange:y=>t(y.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"username",disabled:l})]})]}),c.jsxs("div",{children:[c.jsxs("div",{className:"flex items-center justify-between mb-1",children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300",children:"Password"}),c.jsx(Ee,{to:"/forgot-password",className:"text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Forgot password?"})]}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:s?"text":"password",required:!0,value:n,onChange:y=>r(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:l}),c.jsx("button",{type:"button",onClick:()=>o(!s),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",children:s?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("button",{type:"submit",disabled:l,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:[l&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),l?"Signing in...":"Sign in"]})]}),c.jsxs("div",{className:"mt-6",children:[c.jsx("div",{className:"relative",children:c.jsxs("div",{className:"relative flex justify-center items-center text-sm",children:[c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"}),c.jsx("span",{className:"px-2 text-gray-500",children:"OR"}),c.jsx("div",{className:"flex-1 h-px bg-gray-300 dark:bg-white/10"})]})}),c.jsx("div",{className:"mt-6",children:c.jsxs("button",{onClick:m,type:"button",className:"w-full inline-flex justify-center items-center gap-2 py-2 px-4 border border-gray-300 dark:border-white/10 rounded-lg shadow-sm bg-white dark:bg-white/5 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/10 transition-colors",children:[c.jsxs("svg",{className:"w-5 h-5",xmlns:"http://www.w3.org/2000/svg",x:"0px",y:"0px",width:"25",height:"25",viewBox:"0 0 48 48",children:[c.jsx("path",{fill:"#FFC107",d:"M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"}),c.jsx("path",{fill:"#FF3D00",d:"M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"}),c.jsx("path",{fill:"#4CAF50",d:"M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"}),c.jsx("path",{fill:"#1976D2",d:"M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"})]}),"Sign in with Google"]})})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs("p",{className:"text-sm text-gray-600 dark:text-gray-400",children:["Don't have an account?"," ",c.jsx(Ee,{to:"/register",className:"font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:"Sign up"})]})})]})]})})}function U6(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(""),[i,a]=S.useState(!1),l=async u=>{var d,h;u.preventDefault(),o(""),r(""),a(!0);try{const f=await ae.post("/auth/forgot-password",{email:e});f.data.success?r("Password reset email sent! Please check your inbox."):o(f.data.message||"Failed to send reset email")}catch(f){o(((h=(d=f.response)==null?void 0:d.data)==null?void 0:h.detail)||"Failed to send reset email. Please try again.")}finally{a(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary p-8 rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Forgot Password "}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Enter your email address and we'll send you a link to reset your password"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:l,children:[s&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:s}),n&&c.jsx("div",{className:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 p-3 rounded-lg text-sm",children:n}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Email address"}),c.jsxs("div",{className:"relative",children:[c.jsx(vu,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:"email",required:!0,value:e,onChange:u=>t(u.target.value),className:"w-full pl-10 pr-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"you@example.com",disabled:i})]})]}),c.jsxs("button",{type:"submit",disabled:i,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:[i&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),i?"Sending...":"Send Reset Link"]})]}),c.jsx("div",{className:"mt-6 text-center",children:c.jsxs(Ee,{to:"/login",className:"inline-flex items-center gap-2 text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400",children:[c.jsx(lR,{className:"w-4 h-4"}),"Back to Sign In"]})})]})})})}function W6(){const[e,t]=S.useState(""),[n,r]=S.useState(""),[s,o]=S.useState(!1),[i,a]=S.useState(!1),[l,u]=S.useState(""),[d,h]=S.useState(!1),[f]=m1(),p=Is(),g=f.get("token");S.useEffect(()=>{g||u("Invalid or missing reset token")},[g]);const m=async y=>{var x,v;if(y.preventDefault(),u(""),e!==n){u("Passwords do not match");return}if(!g){u("Invalid reset token");return}h(!0);try{await ae.post("/auth/reset-password",{token:g,new_password:e}),p("/login",{state:{message:"Password reset successful! Please sign in with your new password."}})}catch(b){u(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Failed to reset password. The link may have expired.")}finally{h(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4",children:c.jsx("div",{className:"max-w-md w-full space-y-8",children:c.jsxs("div",{className:"bg-white dark:bg-secondary p-8 rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 border border-gray-100 dark:border-white/5 backdrop-blur-sm",children:[c.jsxs("div",{className:"gap-2 flex flex-col items-center justify-center mb-6",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Reset Password "}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Enter your new password below"})]}),c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[l&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:l}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:s?"text":"password",required:!0,value:e,onChange:y=>t(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:d||!g}),c.jsx("button",{type:"button",onClick:()=>o(!s),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:d||!g,children:s?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Confirm New Password"}),c.jsxs("div",{className:"relative",children:[c.jsx(Qn,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400"}),c.jsx("input",{type:i?"text":"password",required:!0,value:n,onChange:y=>r(y.target.value),className:"w-full pl-10 pr-12 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"••••••••",disabled:d||!g}),c.jsx("button",{type:"button",onClick:()=>a(!i),className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",disabled:d||!g,children:i?c.jsx(Dr,{className:"w-5 h-5"}):c.jsx(Ir,{className:"w-5 h-5"})})]})]}),c.jsx("button",{type:"submit",disabled:d||!g,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:d?"Resetting Password...":"Reset Password"})]})]})})})}const G6=["NGO","Government","Private Sector","Research","Individual","Other"],Eb=["Health","Agriculture","Energy","Environment","Education","Governance"];function q6(){const{user:e,checkAuth:t}=Qr(),n=Is(),[r,s]=S.useState({full_name:(e==null?void 0:e.full_name)||"",organization:(e==null?void 0:e.organization)==="Unknown"?"":(e==null?void 0:e.organization)||"",organization_type:(e==null?void 0:e.organization_type)||""}),[o,i]=S.useState((e==null?void 0:e.sector)||[]),[a,l]=S.useState(""),[u,d]=S.useState(!1),[h,f]=S.useState(""),p=y=>{i(x=>x.includes(y)?x.filter(v=>v!==y):[...x,y])},g=()=>{const y=a.trim();y&&!o.includes(y)&&(i(x=>[...x,y]),l(""))},m=async y=>{var x,v;y.preventDefault(),f(""),d(!0);try{await ae.put("/auth/profile",{full_name:r.full_name||void 0,organization:r.organization||void 0,organization_type:r.organization_type||void 0,sector:o.length>0?o:void 0}),await t(),n("/dashboard")}catch(b){f(((v=(x=b.response)==null?void 0:x.data)==null?void 0:v.detail)||"Failed to update profile. Please try again.")}finally{d(!1)}};return c.jsx("div",{className:"min-h-screen flex items-center justify-center bg-gray-50 dark:bg-black px-4 py-12",children:c.jsxs("div",{className:"max-w-md w-full space-y-8",children:[c.jsxs("div",{className:"text-center",children:[c.jsx("img",{src:"/logo.png",alt:"Sunbird AI",className:"h-10 w-10 rounded-full object-cover mx-auto mb-3"}),c.jsx("h2",{className:"text-2xl font-bold text-gray-900 dark:text-white",children:"Complete Your Profile"}),c.jsx("p",{className:"mt-2 text-sm text-gray-600 dark:text-gray-400",children:"Help us understand how you're using Sunbird AI so we can serve you better."})]}),c.jsxs("div",{className:"bg-white dark:bg-secondary rounded-2xl shadow-lg dark:shadow-lg dark:shadow-black/10 p-8 border border-gray-100 dark:border-white/5",children:[c.jsxs("form",{className:"space-y-6",onSubmit:m,children:[h&&c.jsx("div",{className:"bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-lg text-sm",children:h}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Full Name"}),c.jsx("input",{type:"text",value:r.full_name,onChange:y=>s({...r,full_name:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"John Doe",disabled:u})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Name"}),c.jsx("input",{type:"text",value:r.organization,onChange:y=>s({...r,organization:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Sunbird AI",disabled:u})]}),c.jsxs("div",{children:[c.jsx("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:"Organization Type"}),c.jsxs("select",{value:r.organization_type,onChange:y=>s({...r,organization_type:y.target.value}),className:"w-full px-4 py-2 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white appearance-none",disabled:u,children:[c.jsx("option",{value:"",children:"Select type..."}),G6.map(y=>c.jsx("option",{value:y,children:y},y))]})]}),c.jsxs("div",{children:[c.jsxs("label",{className:"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",children:["Impact Sectors ",c.jsx("span",{className:"text-gray-400 font-normal",children:"(select all that apply)"})]}),c.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:[...Eb,...o.filter(y=>!Eb.includes(y))].map(y=>c.jsxs("button",{type:"button",onClick:()=>p(y),disabled:u,className:`px-3 py-1.5 rounded-full text-sm border transition-colors ${o.includes(y)?"border-primary-500 bg-primary-500/10 text-primary-600 dark:text-primary-400":"border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5"}`,children:[y," ",o.includes(y)&&"✓"]},y))}),c.jsxs("div",{className:"flex gap-2 mt-2",children:[c.jsx("input",{type:"text",value:a,onChange:y=>l(y.target.value),onKeyDown:y=>y.key==="Enter"&&(y.preventDefault(),g()),className:"flex-1 px-3 py-1.5 bg-white dark:bg-black/50 border border-gray-200 dark:border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 dark:text-white text-sm placeholder-gray-400 dark:placeholder-gray-600",placeholder:"Add custom sector...",disabled:u}),c.jsx("button",{type:"button",onClick:g,disabled:u,className:"px-3 py-1.5 text-sm border border-gray-200 dark:border-white/10 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors",children:"Add"})]})]}),c.jsxs("button",{type:"submit",disabled:u,className:"w-full flex justify-center items-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors shadow-lg shadow-primary-500/20 disabled:opacity-50 disabled:cursor-not-allowed",children:[u&&c.jsx(Da,{className:"w-4 h-4 animate-spin"}),u?"Saving...":"Save & Continue to Dashboard"]})]}),c.jsx("div",{className:"mt-4 text-center",children:c.jsx("button",{onClick:()=>n("/dashboard"),className:"text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors",children:"Skip for now →"})})]})]})})}function K6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black flex flex-col",children:[c.jsx(Bu,{}),c.jsx("main",{className:"flex-1 pt-24 pb-16 px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"max-w-4xl mx-auto",children:[c.jsx("h1",{className:"text-4xl font-bold text-gray-900 dark:text-white mb-8",children:"Privacy Policy"}),c.jsxs("div",{className:"space-y-8 text-gray-700 dark:text-gray-300",children:[c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Introduction"}),c.jsx("p",{className:"leading-relaxed",children:"Welcome to the Privacy Policy of Sunbird AI. We understand that privacy online is important to users of our services, especially when utilizing our WhatsApp translation bot. This statement governs our privacy policies with respect to the collection, use, and disclosure of personal information when using our services."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Personally Identifiable Information"}),c.jsx("p",{className:"leading-relaxed",children:"Personally Identifiable Information refers to any information that identifies or can be used to identify, contact, or locate the person to whom such information pertains, including, but not limited to, name, address, phone number, email address, IP address, location, and browser."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"What Personally Identifiable Information is collected?"}),c.jsx("p",{className:"leading-relaxed",children:"We may collect basic user profile information from all users of our services. Additional information may be collected from users of our WhatsApp translation bot, including but not limited to, the content of messages for translation purposes."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"How is Personally Identifiable Information stored?"}),c.jsx("p",{className:"leading-relaxed",children:"Personally Identifiable Information collected by Sunbird AI is securely stored and is not accessible to third parties or employees of Sunbird AI except for use as indicated above."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"What choices are available to users regarding collection, use, and distribution of the information?"}),c.jsx("p",{className:"leading-relaxed",children:"Users may opt-out of certain data collection practices as outlined in this Privacy Policy by contacting Sunbird AI."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Changes to this Privacy Policy"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI reserves the right to update or change our Privacy Policy at any time. Users will be notified of any changes by posting the new Privacy Policy on this page."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Contact Us"}),c.jsxs("p",{className:"leading-relaxed",children:["If you have any questions about this Privacy Policy, please contact us at ",c.jsx("a",{href:"mailto:info@sunbird.ai",className:"text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 underline",children:"info@sunbird.ai"})]})]})]})]})}),c.jsx($u,{})]})}function Y6(){return c.jsxs("div",{className:"min-h-screen bg-white dark:bg-black flex flex-col",children:[c.jsx(Bu,{}),c.jsx("main",{className:"flex-1 pt-24 pb-16 px-4 sm:px-6 lg:px-8",children:c.jsxs("div",{className:"max-w-4xl mx-auto",children:[c.jsx("h1",{className:"text-4xl font-bold text-gray-900 dark:text-white mb-8",children:"Terms of Service"}),c.jsxs("div",{className:"space-y-8 text-gray-700 dark:text-gray-300",children:[c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Agreement"}),c.jsx("p",{className:"leading-relaxed",children:"By accessing or using the services provided by Sunbird AI, you agree to abide by these Terms of Service. These Terms apply to all visitors, users, and others who access or use our services."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Use of Services"}),c.jsx("p",{className:"leading-relaxed",children:'Our services, including the WhatsApp translation bot, are provided on an "as is" and "as available" basis. Users are solely responsible for their use of the services and any consequences thereof.'})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Intellectual Property"}),c.jsx("p",{className:"leading-relaxed",children:"All intellectual property rights associated with the services provided by Sunbird AI, including but not limited to, the WhatsApp translation bot, are owned by Sunbird AI. Users are granted a limited, non-exclusive, non-transferable license to use the services for personal or non-commercial purposes."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Limitation of Liability"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI shall not be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly, or any loss of data, use, goodwill, or other intangible losses resulting from (i) your access to or use of or inability to access or use the services; (ii) any conduct or content of any third party on the services; (iii) any content obtained from the services; or (iv) unauthorized access, use, or alteration of your transmissions or content."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Changes to Terms of Service"}),c.jsx("p",{className:"leading-relaxed",children:"Sunbird AI reserves the right to update or change these Terms of Service at any time. Users will be notified of any changes by posting the new Terms of Service on this page."})]}),c.jsxs("div",{children:[c.jsx("h2",{className:"text-2xl font-semibold text-gray-900 dark:text-white mb-4",children:"Contact Us"}),c.jsxs("p",{className:"leading-relaxed",children:["If you have any questions about these Terms of Service, please contact us at ",c.jsx("a",{href:"mailto:info@sunbird.ai",className:"text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 underline",children:"info@sunbird.ai"})]})]})]})]})}),c.jsx($u,{})]})}function X6(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Q6(e,t){if(e==null)return{};var n,r,s=X6(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;re.length)&&(t=e.length);for(var n=0,r=Array(t);n=4)return[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]}var sh={};function oF(e){if(e.length===0||e.length===1)return e;var t=e.join(".");return sh[t]||(sh[t]=sF(e)),sh[t]}function iF(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=e.filter(function(o){return o!=="token"}),s=oF(r);return s.reduce(function(o,i){return fo(fo({},o),n[i])},t)}function Ab(e){return e.join(" ")}function aF(e,t){var n=0;return function(r){return n+=1,r.map(function(s,o){return US({node:s,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(o)})})}}function US(e){var t=e.node,n=e.stylesheet,r=e.style,s=r===void 0?{}:r,o=e.useInlineStyles,i=e.key,a=t.properties,l=t.type,u=t.tagName,d=t.value;if(l==="text")return d;if(u){var h=aF(n,o),f;if(!o)f=fo(fo({},a),{},{className:Ab(a.className)});else{var p=Object.keys(n).reduce(function(x,v){return v.split(".").forEach(function(b){x.includes(b)||x.push(b)}),x},[]),g=a.className&&a.className.includes("token")?["token"]:[],m=a.className&&g.concat(a.className.filter(function(x){return!p.includes(x)}));f=fo(fo({},a),{},{className:Ab(m)||void 0,style:iF(a.className,Object.assign({},a.style,s),n)})}var y=h(t.children);return z.createElement(u,Yf({key:i},f),y)}}const lF=(function(e,t){var n=e.listLanguages();return n.indexOf(t)!==-1});var cF=["language","children","style","customStyle","codeTagProps","useInlineStyles","showLineNumbers","showInlineLineNumbers","startingLineNumber","lineNumberContainerStyle","lineNumberStyle","wrapLines","wrapLongLines","lineProps","renderer","PreTag","CodeTag","code","astGenerator"];function Mb(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(s){return Object.getOwnPropertyDescriptor(e,s).enumerable})),n.push.apply(n,r)}return n}function Cr(e){for(var t=1;t1&&arguments[1]!==void 0?arguments[1]:[],n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:[];e.length===void 0&&(e=[e]);for(var r=0;r2&&arguments[2]!==void 0?arguments[2]:[];return rc({children:w,lineNumber:j,lineNumberStyle:a,largestLineNumber:i,showInlineLineNumbers:s,lineProps:n,className:N,showLineNumbers:r,wrapLongLines:l,wrapLines:t})}function m(w,j){if(r&&j&&s){var N=GS(a,j,i);w.unshift(WS(j,N))}return w}function y(w,j){var N=arguments.length>2&&arguments[2]!==void 0?arguments[2]:[];return t||N.length>0?g(w,j,N):m(w,j)}for(var x=function(){var j=d[p],N=j.children[0].value,_=dF(N);if(_){var P=N.split(`
diff --git a/app/static/react_build/index.html b/app/static/react_build/index.html
index 1ab8f0b8..94d294cf 100644
--- a/app/static/react_build/index.html
+++ b/app/static/react_build/index.html
@@ -5,7 +5,7 @@
Sunbird AI API
-
+
diff --git a/docs/billing-analytics.md b/docs/billing-analytics.md
index 483b0f52..9e780fdb 100644
--- a/docs/billing-analytics.md
+++ b/docs/billing-analytics.md
@@ -28,6 +28,17 @@ Environment variables:
credentials with `ce:GetCostAndUsage` permission (cloud category). Read by boto3 from env.
- `AWS_REGION` — optional, defaults to `us-east-1` (Cost Explorer endpoint).
- `AWS_COST_METRIC` — optional, defaults to `UnblendedCost`.
+- `GCP_BILLING_BQ_TABLE` — fully-qualified BigQuery table for GCP billing export, e.g.
+ `my-project.my_dataset.gcp_billing_export_v1_XXXXXX` (cloud category). Required to
+ enable GCP billing. Prereq: Cloud Billing export to BigQuery must be enabled (standard
+ usage-cost export; table name matches `gcp_billing_export_v1_*`).
+- `GCP_BILLING_PROJECT_ID` — optional GCP project ID to bill BigQuery queries against;
+ falls back to `GCP_PROJECT_ID` if unset.
+- GCP credentials: resolved via Application Default Credentials (`GOOGLE_APPLICATION_CREDENTIALS`
+ env var pointing to a service-account key, or Cloud Run workload identity automatically).
+ The service account needs **BigQuery Data Viewer** + **BigQuery Job User** on the billing
+ dataset/project. Note: BigQuery is billed by bytes scanned (first 1 TB/month free); the
+ existing cache keeps query volume low.
## Field meanings
@@ -53,11 +64,18 @@ The dashboard is split into categories, selected by the `category` query param
amortizes each contract's cost and GPU-hours evenly across the days it ran into per-day
records; the Training Jobs table groups those back into one row per contract. Vast.ai
storage is billed as cost, not GB.
-- **Cloud** — AWS (Cost Explorer). Costs are reported as UnblendedCost, broken down by service
- and usage type (one record per service/usage-type/bucket). The graph shows cost per service
- over time; the breakdown table toggles Service ↔ Usage-type and is searchable. Hourly
- granularity is limited to the last 14 days (AWS constraint); each Cost Explorer API call is
- billed by AWS, so results are cached. GCP and Heroku remain future additions to this category.
+- **Cloud** — AWS + GCP cloud infrastructure costs. Use the `provider` filter (`all | aws | gcp`)
+ to scope to a single provider or view both together.
+ - **AWS** (Cost Explorer): costs reported as UnblendedCost, broken down by service and usage
+ type (one record per service/usage-type/bucket). The graph shows cost per service over time;
+ the breakdown table toggles Service ↔ Usage-type and is searchable. Hourly granularity is
+ limited to the last 14 days (AWS constraint); each Cost Explorer API call is billed by AWS,
+ so results are cached.
+ - **GCP** (Cloud Billing export in BigQuery): costs reported as net cost (list price after
+ credits and discounts), broken down by service and SKU (SKU shown under Usage-type). Billing
+ export data can lag up to about a day, so the current day may be partial. Each refresh runs
+ a BigQuery query; results are cached. No 14-day hourly limit. `active_services` counts
+ distinct services across both AWS and GCP.
## Endpoints
diff --git a/frontend/src/hooks/useBillingAnalytics.ts b/frontend/src/hooks/useBillingAnalytics.ts
index 98f661cc..33f0aa88 100644
--- a/frontend/src/hooks/useBillingAnalytics.ts
+++ b/frontend/src/hooks/useBillingAnalytics.ts
@@ -6,7 +6,7 @@ const BASE = '/api/admin/analytics/billing';
export interface BillingFilters {
category: 'inference' | 'training' | 'cloud';
- provider: 'all' | 'runpod' | 'modal' | 'vastai' | 'aws';
+ provider: 'all' | 'runpod' | 'modal' | 'vastai' | 'aws' | 'gcp';
range: string;
resolution: 'hour' | 'day' | 'week' | 'month' | 'year';
groupBy?: string;
diff --git a/frontend/src/pages/AdminBilling.tsx b/frontend/src/pages/AdminBilling.tsx
index f2904f18..4a65b8a3 100644
--- a/frontend/src/pages/AdminBilling.tsx
+++ b/frontend/src/pages/AdminBilling.tsx
@@ -145,7 +145,7 @@ export default function AdminBilling() {
{filters.category === 'training'
? 'Vast.ai training spend, GPU hours, and per-job breakdown.'
: filters.category === 'cloud'
- ? 'AWS spend by service and usage type, from Cost Explorer.'
+ ? 'AWS & GCP spend by service and usage type.'
: 'Runpod & Modal spend, runtime, and storage analytics.'}
@@ -162,7 +162,7 @@ export default function AdminBilling() {
{([
['inference', 'Inference (Runpod & Modal)', false],
['training', 'Training (Vast.ai)', false],
- ['cloud', 'Cloud (AWS)', false],
+ ['cloud', 'Cloud', false],
] as const).map(([cat, label, disabled]) => (