@burdenoff/microfe-ggnomad 2026.730.2 → 2026.801.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/ggnomad/GGNomadRoutes.js +1 -1
  2. package/dist/ggnomad/GGNomadRoutes.js.map +1 -1
  3. package/dist/ggnomad/components/BookingPanel.js +1 -1
  4. package/dist/ggnomad/components/BookingPanel.js.map +1 -1
  5. package/dist/ggnomad/components/EntityCard.js +1 -1
  6. package/dist/ggnomad/components/EntityCard.js.map +1 -1
  7. package/dist/ggnomad/pages/ActivityDetailsPage.js +1 -1
  8. package/dist/ggnomad/pages/ActivityDetailsPage.js.map +1 -1
  9. package/dist/ggnomad/pages/BookingsPage.js +1 -1
  10. package/dist/ggnomad/pages/BookingsPage.js.map +1 -1
  11. package/dist/ggnomad/pages/DashboardPage.js +1 -1
  12. package/dist/ggnomad/pages/DashboardPage.js.map +1 -1
  13. package/dist/ggnomad/pages/EventDetailsPage.js +1 -1
  14. package/dist/ggnomad/pages/EventDetailsPage.js.map +1 -1
  15. package/dist/ggnomad/pages/PropertyDetailsPage.js +1 -1
  16. package/dist/ggnomad/pages/PropertyDetailsPage.js.map +1 -1
  17. package/dist/ggnomad/pages/ProviderPage.js +1 -1
  18. package/dist/ggnomad/pages/ProviderPage.js.map +1 -1
  19. package/dist/ggnomad/pages/StorefrontPage.js +1 -1
  20. package/dist/ggnomad/pages/StorefrontPage.js.map +1 -1
  21. package/dist/ggnomad/pages/StorefrontPublicPage.js +1 -1
  22. package/dist/ggnomad/pages/StorefrontPublicPage.js.map +1 -1
  23. package/dist/ggnomad/pages/TourDetailsPage.js +1 -1
  24. package/dist/ggnomad/pages/TourDetailsPage.js.map +1 -1
  25. package/dist/ggnomad/pages/TripPlanDetailPage.js +1 -1
  26. package/dist/ggnomad/pages/TripPlanDetailPage.js.map +1 -1
  27. package/dist/ggnomad/pages/TripsPage.js +1 -1
  28. package/dist/ggnomad/pages/TripsPage.js.map +1 -1
  29. package/dist/ggnomad/providers/GGNomadProvider.js +1 -1
  30. package/dist/ggnomad/providers/GGNomadProvider.js.map +1 -1
  31. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/PropertyDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { Hotel, Pencil } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_PROPERTY_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { PageShell } from './PageShell';\nimport {\n DetailRow,\n SectionCard,\n DetailHero,\n BookingPanel,\n ReviewsSection,\n ListingEditDialog,\n} from '../components';\n\nexport function PropertyDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_PROPERTY_QUERY as TypedDocumentNode<\n {\n ggnomadProperty: {\n id: string;\n name: string;\n type: string;\n description?: string;\n currency: string;\n pricePerNight: number;\n status?: string;\n maxGuests: number;\n rating?: number;\n provider?: { name: string };\n images?: string[];\n } | null;\n },\n { id: string }\n >,\n { variables: { id }, skip: !id }\n );\n const property = data?.ggnomadProperty;\n\n return (\n <PageShell\n title={property?.name ?? t('ggnomad.property.fallbackTitle', 'Property details')}\n subtitle={t('ggnomad.property.subtitle', 'Detailed hospitality listing view')}\n >\n {!property ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.property.notFoundTitle', 'No property found')}\n description={t(\n 'ggnomad.property.notFoundDescription',\n 'This property is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n <DetailHero image={property.images?.[0]} alt={property.name} />\n <PagePurpose icon={<Hotel className=\"size-4\" />}>\n {t(\n 'ggnomad.property.purpose',\n 'Everything you need to decide on this stay — its type, description, nightly price, guest capacity, rating and the provider behind it — before you reserve it.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-property-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.property.next.browse', 'Compare other stays'),\n description: t(\n 'ggnomad.property.next.browseDesc',\n 'Go back to hospitality listings to compare options.'\n ),\n icon: <Hotel className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'hospitality')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <SectionCard title={t('ggnomad.property.about', 'About')}>\n <p className=\"text-sm text-text-secondary\">{t('ggnomad.property.type', 'Type')}</p>\n <p className=\"text-text-primary\">{property.type}</p>\n <p className=\"mt-3 text-sm text-text-secondary\">\n {t('ggnomad.property.description', 'Description')}\n </p>\n <p className=\"text-text-primary\">\n {property.description ?? t('ggnomad.property.noDescription', 'No description')}\n </p>\n </SectionCard>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.property.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.property.editListing', 'Edit listing')}\n title={t('ggnomad.property.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow\n label={t('ggnomad.property.price', 'Price')}\n value={`${property.currency} ${Number(property.pricePerNight).toFixed(2)}`}\n />\n <DetailRow\n label={t('ggnomad.property.guests', 'Guests')}\n value={String(property.maxGuests)}\n />\n <DetailRow\n label={t('ggnomad.property.rating', 'Rating')}\n value={String(property.rating ?? t('ggnomad.property.noRating', 'N/A'))}\n />\n <DetailRow\n label={t('ggnomad.property.provider', 'Provider')}\n value={\n property.provider?.name ?? t('ggnomad.property.unassigned', 'Unassigned')\n }\n />\n </dl>\n </GlassCard>\n <ReviewsSection targetType=\"PROPERTY\" targetId={property.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"PROPERTY\"\n itemId={property.id ?? id}\n itemName={property.name}\n unitPrice={property.pricePerNight ?? 0}\n currency={property.currency ?? 'USD'}\n nights={1}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"PROPERTY\"\n id={property.id ?? id}\n initial={{\n name: property.name,\n description: property.description,\n pricePerNight: property.pricePerNight,\n status: property.status,\n images: property.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PropertyDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/PropertyDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router';\nimport { Hotel, Pencil } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_PROPERTY_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { PageShell } from './PageShell';\nimport {\n DetailRow,\n SectionCard,\n DetailHero,\n BookingPanel,\n ReviewsSection,\n ListingEditDialog,\n} from '../components';\n\nexport function PropertyDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_PROPERTY_QUERY as TypedDocumentNode<\n {\n ggnomadProperty: {\n id: string;\n name: string;\n type: string;\n description?: string;\n currency: string;\n pricePerNight: number;\n status?: string;\n maxGuests: number;\n rating?: number;\n provider?: { name: string };\n images?: string[];\n } | null;\n },\n { id: string }\n >,\n { variables: { id }, skip: !id }\n );\n const property = data?.ggnomadProperty;\n\n return (\n <PageShell\n title={property?.name ?? t('ggnomad.property.fallbackTitle', 'Property details')}\n subtitle={t('ggnomad.property.subtitle', 'Detailed hospitality listing view')}\n >\n {!property ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.property.notFoundTitle', 'No property found')}\n description={t(\n 'ggnomad.property.notFoundDescription',\n 'This property is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n <DetailHero image={property.images?.[0]} alt={property.name} />\n <PagePurpose icon={<Hotel className=\"size-4\" />}>\n {t(\n 'ggnomad.property.purpose',\n 'Everything you need to decide on this stay — its type, description, nightly price, guest capacity, rating and the provider behind it — before you reserve it.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-property-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.property.next.browse', 'Compare other stays'),\n description: t(\n 'ggnomad.property.next.browseDesc',\n 'Go back to hospitality listings to compare options.'\n ),\n icon: <Hotel className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'hospitality')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <SectionCard title={t('ggnomad.property.about', 'About')}>\n <p className=\"text-sm text-text-secondary\">{t('ggnomad.property.type', 'Type')}</p>\n <p className=\"text-text-primary\">{property.type}</p>\n <p className=\"mt-3 text-sm text-text-secondary\">\n {t('ggnomad.property.description', 'Description')}\n </p>\n <p className=\"text-text-primary\">\n {property.description ?? t('ggnomad.property.noDescription', 'No description')}\n </p>\n </SectionCard>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.property.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.property.editListing', 'Edit listing')}\n title={t('ggnomad.property.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow\n label={t('ggnomad.property.price', 'Price')}\n value={`${property.currency} ${Number(property.pricePerNight).toFixed(2)}`}\n />\n <DetailRow\n label={t('ggnomad.property.guests', 'Guests')}\n value={String(property.maxGuests)}\n />\n <DetailRow\n label={t('ggnomad.property.rating', 'Rating')}\n value={String(property.rating ?? t('ggnomad.property.noRating', 'N/A'))}\n />\n <DetailRow\n label={t('ggnomad.property.provider', 'Provider')}\n value={\n property.provider?.name ?? t('ggnomad.property.unassigned', 'Unassigned')\n }\n />\n </dl>\n </GlassCard>\n <ReviewsSection targetType=\"PROPERTY\" targetId={property.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"PROPERTY\"\n itemId={property.id ?? id}\n itemName={property.name}\n unitPrice={property.pricePerNight ?? 0}\n currency={property.currency ?? 'USD'}\n nights={1}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"PROPERTY\"\n id={property.id ?? id}\n initial={{\n name: property.name,\n description: property.description,\n pricePerNight: property.pricePerNight,\n status: property.status,\n images: property.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
@@ -7,7 +7,7 @@ import "../components/index.js";
7
7
  import { useState as a } from "react";
8
8
  import { Briefcase as o, Store as s } from "lucide-react";
9
9
  import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
- import { Link as l } from "react-router-dom";
10
+ import { Link as l } from "react-router";
11
11
  import { useQuery as u } from "@apollo/client/react";
12
12
  import { GlassCard as d, IllustratedEmptyState as f, PagePurpose as p } from "@burdenoff/fe-libs/ui";
13
13
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"ProviderPage.js","names":[],"sources":["../../../src/ggnomad/pages/ProviderPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { Link } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Briefcase, Store } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_PROVIDERS_QUERY } from '../graphql';\nimport { PageShell } from './PageShell';\nimport { EntityCard, LoadMoreButton, StatusBadge } from '../components';\n\nexport function ProviderPage() {\n const { t } = useI18n();\n const [limit, setLimit] = useState(12);\n const { data } = useQuery(\n GGNOMAD_PROVIDERS_QUERY as TypedDocumentNode<\n {\n ggnomadProviders: Array<{\n id: string;\n name: string;\n type: string;\n status: string;\n listingCount: number;\n totalRevenue: number;\n rating?: number;\n }>;\n },\n { limit: number; offset: number }\n >,\n { variables: { limit, offset: 0 } }\n );\n const providers = data?.ggnomadProviders ?? [];\n\n return (\n <PageShell\n title={t('ggnomad.provider.title', 'Provider Dashboard')}\n titleAccent={t('ggnomad.provider.title.accent', 'Provider')}\n subtitle={t('ggnomad.provider.subtitle', 'B2B provider operations and onboarding metrics')}\n >\n <PagePurpose icon={<Briefcase className=\"size-4\" />}>\n {t(\n 'ggnomad.provider.purpose',\n 'Track the supply side of the marketplace — the hotels, tour operators and venues that publish inventory. Use it to monitor each provider’s status, listing count, revenue and rating, and to spot who needs onboarding attention.'\n )}\n </PagePurpose>\n\n {providers.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={t('ggnomad.provider.emptyTitle', 'No providers onboarded')}\n description={t(\n 'ggnomad.provider.emptyDescription',\n 'Onboarded B2B providers and their performance will be tracked here.'\n )}\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <h2 className=\"mb-4 text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.provider.onboardedProviders', 'Onboarded providers')}\n </h2>\n <div className=\"grid gap-3 sm:grid-cols-2 xl:grid-cols-3\">\n {providers.map((provider) => (\n <EntityCard\n key={provider.id}\n title={provider.name}\n meta={provider.type}\n badge={<StatusBadge status={provider.status} live={provider.status === 'ACTIVE'} />}\n footer={\n <dl className=\"grid grid-cols-3 gap-2 text-xs\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.listings', 'Listings')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {provider.listingCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.revenue', 'Revenue')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n ${Number(provider.totalRevenue).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.rating', 'Rating')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {provider.rating ?? t('ggnomad.provider.noRating', 'N/A')}\n </dd>\n </div>\n <div className=\"col-span-3 mt-1 border-t border-border-seam pt-2\">\n <Link\n to={`${provider.id}/storefront`}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-action-primary-bg hover:underline\"\n >\n <Store className=\"size-3.5\" />\n {t('ggnomad.provider.manageStorefront', 'Manage storefront')}\n </Link>\n </div>\n </dl>\n }\n />\n ))}\n </div>\n <LoadMoreButton\n visible={providers.length >= limit}\n onLoadMore={() => setLimit((l) => l + 12)}\n />\n </GlassCard>\n )}\n </PageShell>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,IAAe;CAC7B,IAAM,EAAE,SAAM,EAAQ,GAChB,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,EAAE,YAAS,EACf,GAcA,EAAE,WAAW;EAAE;EAAO,QAAQ;CAAE,EAAE,CACpC,GACM,IAAY,GAAM,oBAAoB,CAAC;CAE7C,OACE,kBAAC,GAAD;EACE,OAAO,EAAE,0BAA0B,oBAAoB;EACvD,aAAa,EAAE,iCAAiC,UAAU;EAC1D,UAAU,EAAE,6BAA6B,gDAAgD;YAH3F,CAKE,kBAAC,GAAD;GAAa,MAAM,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA;aAC/C,EACC,4BACA,mOACF;EACW,CAAA,GAEZ,EAAU,WAAW,IACpB,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,+BAA+B,wBAAwB;GAChE,aAAa,EACX,qCACA,qEACF;EACD,CAAA,IAED,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAA5C;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,uCAAuC,qBAAqB;IAC7D,CAAA;IACJ,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MACd,kBAAC,GAAD;MAEE,OAAO,EAAS;MAChB,MAAM,EAAS;MACf,OAAO,kBAAC,GAAD;OAAa,QAAQ,EAAS;OAAQ,MAAM,EAAS,WAAW;MAAW,CAAA;MAClF,QACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,6BAA6B,UAAU;QACxC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAS;QACR,CAAA,CACD,EAAA,CAAA;QACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,4BAA4B,SAAS;QACtC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBAAd,CAAkE,KAC9D,OAAO,EAAS,YAAY,EAAE,eAAe,CAC7C;UACD,EAAA,CAAA;QACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,2BAA2B,QAAQ;QACpC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAS,UAAU,EAAE,6BAA6B,KAAK;QACtD,CAAA,CACD,EAAA,CAAA;QACL,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,GAAD;UACE,IAAI,GAAG,EAAS,GAAG;UACnB,WAAU;oBAFZ,CAIE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,GAC5B,EAAE,qCAAqC,mBAAmB,CACvD;;QACH,CAAA;OACH;;KAEP,GAzCM,EAAS,EAyCf,CACF;IACE,CAAA;IACL,kBAAC,GAAD;KACE,SAAS,EAAU,UAAU;KAC7B,kBAAkB,GAAU,MAAM,IAAI,EAAE;IACzC,CAAA;GACQ;IAEJ;;AAEf"}
1
+ {"version":3,"file":"ProviderPage.js","names":[],"sources":["../../../src/ggnomad/pages/ProviderPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { Link } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Briefcase, Store } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_PROVIDERS_QUERY } from '../graphql';\nimport { PageShell } from './PageShell';\nimport { EntityCard, LoadMoreButton, StatusBadge } from '../components';\n\nexport function ProviderPage() {\n const { t } = useI18n();\n const [limit, setLimit] = useState(12);\n const { data } = useQuery(\n GGNOMAD_PROVIDERS_QUERY as TypedDocumentNode<\n {\n ggnomadProviders: Array<{\n id: string;\n name: string;\n type: string;\n status: string;\n listingCount: number;\n totalRevenue: number;\n rating?: number;\n }>;\n },\n { limit: number; offset: number }\n >,\n { variables: { limit, offset: 0 } }\n );\n const providers = data?.ggnomadProviders ?? [];\n\n return (\n <PageShell\n title={t('ggnomad.provider.title', 'Provider Dashboard')}\n titleAccent={t('ggnomad.provider.title.accent', 'Provider')}\n subtitle={t('ggnomad.provider.subtitle', 'B2B provider operations and onboarding metrics')}\n >\n <PagePurpose icon={<Briefcase className=\"size-4\" />}>\n {t(\n 'ggnomad.provider.purpose',\n 'Track the supply side of the marketplace — the hotels, tour operators and venues that publish inventory. Use it to monitor each provider’s status, listing count, revenue and rating, and to spot who needs onboarding attention.'\n )}\n </PagePurpose>\n\n {providers.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={t('ggnomad.provider.emptyTitle', 'No providers onboarded')}\n description={t(\n 'ggnomad.provider.emptyDescription',\n 'Onboarded B2B providers and their performance will be tracked here.'\n )}\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <h2 className=\"mb-4 text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.provider.onboardedProviders', 'Onboarded providers')}\n </h2>\n <div className=\"grid gap-3 sm:grid-cols-2 xl:grid-cols-3\">\n {providers.map((provider) => (\n <EntityCard\n key={provider.id}\n title={provider.name}\n meta={provider.type}\n badge={<StatusBadge status={provider.status} live={provider.status === 'ACTIVE'} />}\n footer={\n <dl className=\"grid grid-cols-3 gap-2 text-xs\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.listings', 'Listings')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {provider.listingCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.revenue', 'Revenue')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n ${Number(provider.totalRevenue).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('ggnomad.provider.rating', 'Rating')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {provider.rating ?? t('ggnomad.provider.noRating', 'N/A')}\n </dd>\n </div>\n <div className=\"col-span-3 mt-1 border-t border-border-seam pt-2\">\n <Link\n to={`${provider.id}/storefront`}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-action-primary-bg hover:underline\"\n >\n <Store className=\"size-3.5\" />\n {t('ggnomad.provider.manageStorefront', 'Manage storefront')}\n </Link>\n </div>\n </dl>\n }\n />\n ))}\n </div>\n <LoadMoreButton\n visible={providers.length >= limit}\n onLoadMore={() => setLimit((l) => l + 12)}\n />\n </GlassCard>\n )}\n </PageShell>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,IAAe;CAC7B,IAAM,EAAE,SAAM,EAAQ,GAChB,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,EAAE,YAAS,EACf,GAcA,EAAE,WAAW;EAAE;EAAO,QAAQ;CAAE,EAAE,CACpC,GACM,IAAY,GAAM,oBAAoB,CAAC;CAE7C,OACE,kBAAC,GAAD;EACE,OAAO,EAAE,0BAA0B,oBAAoB;EACvD,aAAa,EAAE,iCAAiC,UAAU;EAC1D,UAAU,EAAE,6BAA6B,gDAAgD;YAH3F,CAKE,kBAAC,GAAD;GAAa,MAAM,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA;aAC/C,EACC,4BACA,mOACF;EACW,CAAA,GAEZ,EAAU,WAAW,IACpB,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,+BAA+B,wBAAwB;GAChE,aAAa,EACX,qCACA,qEACF;EACD,CAAA,IAED,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAA5C;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,uCAAuC,qBAAqB;IAC7D,CAAA;IACJ,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MACd,kBAAC,GAAD;MAEE,OAAO,EAAS;MAChB,MAAM,EAAS;MACf,OAAO,kBAAC,GAAD;OAAa,QAAQ,EAAS;OAAQ,MAAM,EAAS,WAAW;MAAW,CAAA;MAClF,QACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,6BAA6B,UAAU;QACxC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAS;QACR,CAAA,CACD,EAAA,CAAA;QACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,4BAA4B,SAAS;QACtC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBAAd,CAAkE,KAC9D,OAAO,EAAS,YAAY,EAAE,eAAe,CAC7C;UACD,EAAA,CAAA;QACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,2BAA2B,QAAQ;QACpC,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAS,UAAU,EAAE,6BAA6B,KAAK;QACtD,CAAA,CACD,EAAA,CAAA;QACL,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,GAAD;UACE,IAAI,GAAG,EAAS,GAAG;UACnB,WAAU;oBAFZ,CAIE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,GAC5B,EAAE,qCAAqC,mBAAmB,CACvD;;QACH,CAAA;OACH;;KAEP,GAzCM,EAAS,EAyCf,CACF;IACE,CAAA;IACL,kBAAC,GAAD;KACE,SAAS,EAAU,UAAU;KAC7B,kBAAkB,GAAU,MAAM,IAAI,EAAE;IACzC,CAAA;GACQ;IAEJ;;AAEf"}
@@ -4,7 +4,7 @@ import { notify as a } from "../utils/notify.js";
4
4
  import { useState as o } from "react";
5
5
  import { Globe as s, Palette as c, Store as l } from "lucide-react";
6
6
  import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { useParams as d } from "react-router-dom";
7
+ import { useParams as d } from "react-router";
8
8
  import { useMutation as f, useQuery as p } from "@apollo/client/react";
9
9
  import { Button as m, GlassCard as te, Input as h, PagePurpose as g, Spinner as _, Textarea as v } from "@burdenoff/fe-libs/ui";
10
10
  import { jsx as y, jsxs as b } from "react/jsx-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"StorefrontPage.js","names":[],"sources":["../../../src/ggnomad/pages/StorefrontPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Globe, Palette, Store } from 'lucide-react';\nimport { Button, GlassCard, Input, PagePurpose, Spinner, Textarea } from '@burdenoff/fe-libs/ui';\n\nimport {\n CREATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n GGNOMAD_OPERATOR_STOREFRONT_QUERY,\n PUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n UNPUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n UPDATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n} from '../graphql';\nimport { PageShell } from './PageShell';\nimport { notify } from '../utils/notify';\n\ntype GgnomadOperatorStorefront = {\n id: string;\n providerId: string;\n slug: string;\n displayName: string;\n logoUrl: string | null;\n primaryColor: string | null;\n aboutText: string | null;\n isPublished: boolean;\n publishedAt: string | null;\n};\n\nconst HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;\nconst SLUG_PATTERN = /^[a-z0-9]([a-z0-9-]{1,78}[a-z0-9])?$/;\n\nconst fieldClass =\n 'mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50';\nconst labelClass = 'block text-sm font-medium text-text-primary';\n\n/**\n * BOFF-4363 — operator storefront settings: create/edit the branding\n * (logo/color/slug/about) for one provider and publish/unpublish it. The\n * right-hand panel renders a live, themeable preview of the branded page a\n * traveler would see at `ggnomadStorefrontBySlug` once published.\n *\n * Custom-domain DNS/SSL provisioning and a drag-and-drop page builder are\n * explicitly out of scope for this pass — see Linear BOFF-4363.\n */\nexport function StorefrontPage() {\n const { t } = useI18n();\n const { providerId = '' } = useParams();\n\n const { data, loading, refetch } = useQuery(\n GGNOMAD_OPERATOR_STOREFRONT_QUERY as TypedDocumentNode<\n { ggnomadOperatorStorefront: GgnomadOperatorStorefront | null },\n { providerId: string }\n >,\n { variables: { providerId }, skip: !providerId }\n );\n const storefront = data?.ggnomadOperatorStorefront ?? null;\n\n const [slug, setSlug] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [logoUrl, setLogoUrl] = useState('');\n const [primaryColor, setPrimaryColor] = useState('#1E88E5');\n const [aboutText, setAboutText] = useState('');\n const [hydrated, setHydrated] = useState(false);\n\n if (storefront && !hydrated) {\n setSlug(storefront.slug);\n setDisplayName(storefront.displayName);\n setLogoUrl(storefront.logoUrl ?? '');\n setPrimaryColor(storefront.primaryColor ?? '#1E88E5');\n setAboutText(storefront.aboutText ?? '');\n setHydrated(true);\n }\n\n const [createStorefront, { loading: creating }] = useMutation(\n CREATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { createGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n {\n input: {\n providerId: string;\n slug: string;\n displayName: string;\n logoUrl?: string | null;\n primaryColor?: string | null;\n aboutText?: string | null;\n };\n }\n >\n );\n const [updateStorefront, { loading: updating }] = useMutation(\n UPDATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { updateGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n {\n id: string;\n input: {\n slug?: string;\n displayName?: string;\n logoUrl?: string | null;\n primaryColor?: string | null;\n aboutText?: string | null;\n };\n }\n >\n );\n const [publishStorefront, { loading: publishing }] = useMutation(\n PUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { publishGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n { id: string }\n >\n );\n const [unpublishStorefront, { loading: unpublishing }] = useMutation(\n UNPUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { unpublishGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n { id: string }\n >\n );\n\n const handleSave = async () => {\n if (!slug.trim() || !SLUG_PATTERN.test(slug.trim())) {\n notify.warning(\n t('ggnomad.storefront.invalidSlugTitle', 'Invalid slug'),\n t(\n 'ggnomad.storefront.invalidSlugBody',\n '3-80 lowercase letters, digits, or hyphens; no leading/trailing hyphen.'\n )\n );\n return;\n }\n if (!displayName.trim()) {\n notify.warning(\n t('ggnomad.storefront.nameRequiredTitle', 'Display name is required'),\n t('ggnomad.storefront.nameRequiredBody', 'Give your storefront a public-facing name.')\n );\n return;\n }\n if (primaryColor.trim() && !HEX_COLOR_PATTERN.test(primaryColor.trim())) {\n notify.warning(\n t('ggnomad.storefront.invalidColorTitle', 'Invalid color'),\n t('ggnomad.storefront.invalidColorBody', 'Use a 6-digit hex color, e.g. #1E88E5.')\n );\n return;\n }\n\n try {\n if (storefront) {\n const result = await updateStorefront({\n variables: {\n id: storefront.id,\n input: {\n slug: slug.trim().toLowerCase(),\n displayName: displayName.trim(),\n logoUrl: logoUrl.trim() || null,\n primaryColor: primaryColor.trim() || null,\n aboutText: aboutText.trim() || null,\n },\n },\n });\n if (result.error) throw result.error;\n notify.success(t('ggnomad.storefront.savedTitle', 'Storefront updated'), displayName);\n } else {\n const result = await createStorefront({\n variables: {\n input: {\n providerId,\n slug: slug.trim().toLowerCase(),\n displayName: displayName.trim(),\n logoUrl: logoUrl.trim() || null,\n primaryColor: primaryColor.trim() || null,\n aboutText: aboutText.trim() || null,\n },\n },\n });\n if (result.error) throw result.error;\n notify.success(t('ggnomad.storefront.createdTitle', 'Storefront created'), displayName);\n }\n await refetch();\n } catch (err) {\n notify.error(\n t('ggnomad.storefront.errorTitle', 'Could not save storefront'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const handleTogglePublish = async () => {\n if (!storefront) return;\n try {\n if (storefront.isPublished) {\n await unpublishStorefront({ variables: { id: storefront.id } });\n notify.success(\n t('ggnomad.storefront.unpublishedTitle', 'Storefront unpublished'),\n t('ggnomad.storefront.unpublishedBody', 'It is no longer visible to the public.')\n );\n } else {\n await publishStorefront({ variables: { id: storefront.id } });\n notify.success(\n t('ggnomad.storefront.publishedTitle', 'Storefront published'),\n t('ggnomad.storefront.publishedBody', 'Your branded page is now publicly reachable.')\n );\n }\n await refetch();\n } catch (err) {\n notify.error(\n t('ggnomad.storefront.errorTitle', 'Could not update storefront'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const saving = creating || updating;\n const previewColor = HEX_COLOR_PATTERN.test(primaryColor.trim())\n ? primaryColor.trim()\n : '#1E88E5';\n\n if (!providerId) {\n return (\n <PageShell\n title={t('ggnomad.storefront.title', 'Operator Storefront')}\n subtitle={t('ggnomad.storefront.missingProvider', 'No provider selected.')}\n >\n <PagePurpose icon={<Store className=\"size-4\" />}>\n {t(\n 'ggnomad.storefront.missingProviderHelp',\n 'Open a provider from the Provider Dashboard and choose “Manage storefront”.'\n )}\n </PagePurpose>\n </PageShell>\n );\n }\n\n return (\n <PageShell\n title={t('ggnomad.storefront.title', 'Operator Storefront')}\n titleAccent={t('ggnomad.storefront.title.accent', 'Storefront')}\n subtitle={t(\n 'ggnomad.storefront.subtitle',\n 'White-label branding for your public listing page — logo, color, slug, and about text.'\n )}\n >\n <PagePurpose icon={<Store className=\"size-4\" />}>\n {t(\n 'ggnomad.storefront.purpose',\n 'Configure how travelers see your business when they visit your branded storefront URL. Publish when ready — draft branding stays private until then. Custom domains and a drag-and-drop builder are on the roadmap, not part of this core.'\n )}\n </PagePurpose>\n\n {loading && !hydrated ? (\n <div className=\"flex justify-center py-10\">\n <Spinner />\n </div>\n ) : (\n <div className=\"grid gap-5 lg:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <h2 className=\"mb-4 flex items-center gap-2 text-lg font-medium tracking-tight text-text-primary\">\n <Palette className=\"size-4\" />\n {t('ggnomad.storefront.brandingHeading', 'Branding')}\n </h2>\n <div className=\"space-y-4\">\n <div>\n <label className={labelClass} htmlFor=\"storefront-slug\">\n {t('ggnomad.storefront.slugLabel', 'Public slug')}\n </label>\n <Input\n id=\"storefront-slug\"\n className={fieldClass}\n value={slug}\n onChange={(e) => setSlug(e.target.value.toLowerCase())}\n placeholder=\"my-eco-stays\"\n disabled={saving}\n />\n <p className=\"mt-1 text-xs text-text-secondary\">\n {t(\n 'ggnomad.storefront.slugHelp',\n 'Lowercase letters, digits, hyphens — 3-80 chars.'\n )}\n </p>\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-name\">\n {t('ggnomad.storefront.nameLabel', 'Display name')}\n </label>\n <Input\n id=\"storefront-name\"\n className={fieldClass}\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n placeholder={t('ggnomad.storefront.namePlaceholder', 'Sunset Eco Stays')}\n disabled={saving}\n />\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-logo\">\n {t('ggnomad.storefront.logoLabel', 'Logo URL')}\n </label>\n <Input\n id=\"storefront-logo\"\n className={fieldClass}\n value={logoUrl}\n onChange={(e) => setLogoUrl(e.target.value)}\n placeholder=\"https://example.com/logo.png\"\n disabled={saving}\n />\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-color\">\n {t('ggnomad.storefront.colorLabel', 'Primary color')}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <input\n id=\"storefront-color\"\n type=\"color\"\n className=\"h-9 w-12 rounded border border-border-seam bg-bg-canvas\"\n value={HEX_COLOR_PATTERN.test(primaryColor) ? primaryColor : '#1E88E5'}\n onChange={(e) => setPrimaryColor(e.target.value)}\n disabled={saving}\n />\n <Input\n className={fieldClass}\n value={primaryColor}\n onChange={(e) => setPrimaryColor(e.target.value)}\n placeholder=\"#1E88E5\"\n disabled={saving}\n />\n </div>\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-about\">\n {t('ggnomad.storefront.aboutLabel', 'About text')}\n </label>\n <Textarea\n id=\"storefront-about\"\n className={fieldClass}\n rows={4}\n value={aboutText}\n onChange={(e) => setAboutText(e.target.value)}\n placeholder={t(\n 'ggnomad.storefront.aboutPlaceholder',\n 'Tell travelers what makes your business worth booking.'\n )}\n disabled={saving}\n />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-3 pt-2\">\n <Button onClick={handleSave} disabled={saving}>\n {storefront\n ? t('ggnomad.storefront.saveButton', 'Save changes')\n : t('ggnomad.storefront.createButton', 'Create storefront')}\n </Button>\n {storefront ? (\n <Button\n variant=\"secondary\"\n onClick={handleTogglePublish}\n disabled={publishing || unpublishing}\n >\n {storefront.isPublished\n ? t('ggnomad.storefront.unpublishButton', 'Unpublish')\n : t('ggnomad.storefront.publishButton', 'Publish')}\n </Button>\n ) : null}\n {storefront?.isPublished ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Globe className=\"size-3.5\" />\n {t('ggnomad.storefront.livePathLabel', 'Live at /store/{slug}').replace(\n '{slug}',\n storefront.slug\n )}\n </span>\n ) : null}\n </div>\n </div>\n </GlassCard>\n\n {/* Live preview — the same visual shape ggnomadStorefrontBySlug renders publicly. */}\n <div\n className=\"overflow-hidden rounded-lg border border-border-seam\"\n style={{ borderTopColor: previewColor, borderTopWidth: 4 }}\n >\n <div className=\"p-5\" style={{ background: `${previewColor}14` }}>\n <div className=\"flex items-center gap-3\">\n {logoUrl ? (\n <img\n src={logoUrl}\n alt=\"\"\n className=\"size-12 rounded object-contain\"\n onError={(e) => {\n (e.currentTarget as HTMLImageElement).style.display = 'none';\n }}\n />\n ) : (\n <div\n className=\"flex size-12 items-center justify-center rounded text-lg font-semibold text-white\"\n style={{ background: previewColor }}\n >\n {(displayName || 'S').slice(0, 1).toUpperCase()}\n </div>\n )}\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {displayName ||\n t('ggnomad.storefront.previewPlaceholderName', 'Your Storefront')}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {slug\n ? `/store/${slug}`\n : t('ggnomad.storefront.previewSlugPlaceholder', '/store/…')}\n </p>\n </div>\n </div>\n {aboutText ? (\n <p className=\"mt-4 text-sm text-text-primary\">{aboutText}</p>\n ) : (\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.storefront.previewNoAbout',\n 'Add an about text to introduce your business.'\n )}\n </p>\n )}\n <div\n className=\"mt-4 inline-block rounded px-3 py-1.5 text-xs font-medium text-white\"\n style={{ background: previewColor }}\n >\n {t('ggnomad.storefront.previewCta', 'Book with us')}\n </div>\n </div>\n <div className=\"border-t border-border-seam bg-bg-surface p-4 text-xs text-text-secondary\">\n {t(\n 'ggnomad.storefront.previewFooter',\n 'ACTIVE properties, tours, events, and activities from this provider render below this banner on the public page.'\n )}\n </div>\n </div>\n </div>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StorefrontPage.js","names":[],"sources":["../../../src/ggnomad/pages/StorefrontPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Globe, Palette, Store } from 'lucide-react';\nimport { Button, GlassCard, Input, PagePurpose, Spinner, Textarea } from '@burdenoff/fe-libs/ui';\n\nimport {\n CREATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n GGNOMAD_OPERATOR_STOREFRONT_QUERY,\n PUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n UNPUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n UPDATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION,\n} from '../graphql';\nimport { PageShell } from './PageShell';\nimport { notify } from '../utils/notify';\n\ntype GgnomadOperatorStorefront = {\n id: string;\n providerId: string;\n slug: string;\n displayName: string;\n logoUrl: string | null;\n primaryColor: string | null;\n aboutText: string | null;\n isPublished: boolean;\n publishedAt: string | null;\n};\n\nconst HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;\nconst SLUG_PATTERN = /^[a-z0-9]([a-z0-9-]{1,78}[a-z0-9])?$/;\n\nconst fieldClass =\n 'mt-1 w-full rounded-md border border-border-seam bg-bg-canvas px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-action-primary-bg focus:outline-none focus:ring-1 focus:ring-action-primary-bg disabled:opacity-50';\nconst labelClass = 'block text-sm font-medium text-text-primary';\n\n/**\n * BOFF-4363 — operator storefront settings: create/edit the branding\n * (logo/color/slug/about) for one provider and publish/unpublish it. The\n * right-hand panel renders a live, themeable preview of the branded page a\n * traveler would see at `ggnomadStorefrontBySlug` once published.\n *\n * Custom-domain DNS/SSL provisioning and a drag-and-drop page builder are\n * explicitly out of scope for this pass — see Linear BOFF-4363.\n */\nexport function StorefrontPage() {\n const { t } = useI18n();\n const { providerId = '' } = useParams();\n\n const { data, loading, refetch } = useQuery(\n GGNOMAD_OPERATOR_STOREFRONT_QUERY as TypedDocumentNode<\n { ggnomadOperatorStorefront: GgnomadOperatorStorefront | null },\n { providerId: string }\n >,\n { variables: { providerId }, skip: !providerId }\n );\n const storefront = data?.ggnomadOperatorStorefront ?? null;\n\n const [slug, setSlug] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [logoUrl, setLogoUrl] = useState('');\n const [primaryColor, setPrimaryColor] = useState('#1E88E5');\n const [aboutText, setAboutText] = useState('');\n const [hydrated, setHydrated] = useState(false);\n\n if (storefront && !hydrated) {\n setSlug(storefront.slug);\n setDisplayName(storefront.displayName);\n setLogoUrl(storefront.logoUrl ?? '');\n setPrimaryColor(storefront.primaryColor ?? '#1E88E5');\n setAboutText(storefront.aboutText ?? '');\n setHydrated(true);\n }\n\n const [createStorefront, { loading: creating }] = useMutation(\n CREATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { createGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n {\n input: {\n providerId: string;\n slug: string;\n displayName: string;\n logoUrl?: string | null;\n primaryColor?: string | null;\n aboutText?: string | null;\n };\n }\n >\n );\n const [updateStorefront, { loading: updating }] = useMutation(\n UPDATE_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { updateGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n {\n id: string;\n input: {\n slug?: string;\n displayName?: string;\n logoUrl?: string | null;\n primaryColor?: string | null;\n aboutText?: string | null;\n };\n }\n >\n );\n const [publishStorefront, { loading: publishing }] = useMutation(\n PUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { publishGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n { id: string }\n >\n );\n const [unpublishStorefront, { loading: unpublishing }] = useMutation(\n UNPUBLISH_GGNOMAD_OPERATOR_STOREFRONT_MUTATION as TypedDocumentNode<\n { unpublishGgnomadOperatorStorefront: GgnomadOperatorStorefront },\n { id: string }\n >\n );\n\n const handleSave = async () => {\n if (!slug.trim() || !SLUG_PATTERN.test(slug.trim())) {\n notify.warning(\n t('ggnomad.storefront.invalidSlugTitle', 'Invalid slug'),\n t(\n 'ggnomad.storefront.invalidSlugBody',\n '3-80 lowercase letters, digits, or hyphens; no leading/trailing hyphen.'\n )\n );\n return;\n }\n if (!displayName.trim()) {\n notify.warning(\n t('ggnomad.storefront.nameRequiredTitle', 'Display name is required'),\n t('ggnomad.storefront.nameRequiredBody', 'Give your storefront a public-facing name.')\n );\n return;\n }\n if (primaryColor.trim() && !HEX_COLOR_PATTERN.test(primaryColor.trim())) {\n notify.warning(\n t('ggnomad.storefront.invalidColorTitle', 'Invalid color'),\n t('ggnomad.storefront.invalidColorBody', 'Use a 6-digit hex color, e.g. #1E88E5.')\n );\n return;\n }\n\n try {\n if (storefront) {\n const result = await updateStorefront({\n variables: {\n id: storefront.id,\n input: {\n slug: slug.trim().toLowerCase(),\n displayName: displayName.trim(),\n logoUrl: logoUrl.trim() || null,\n primaryColor: primaryColor.trim() || null,\n aboutText: aboutText.trim() || null,\n },\n },\n });\n if (result.error) throw result.error;\n notify.success(t('ggnomad.storefront.savedTitle', 'Storefront updated'), displayName);\n } else {\n const result = await createStorefront({\n variables: {\n input: {\n providerId,\n slug: slug.trim().toLowerCase(),\n displayName: displayName.trim(),\n logoUrl: logoUrl.trim() || null,\n primaryColor: primaryColor.trim() || null,\n aboutText: aboutText.trim() || null,\n },\n },\n });\n if (result.error) throw result.error;\n notify.success(t('ggnomad.storefront.createdTitle', 'Storefront created'), displayName);\n }\n await refetch();\n } catch (err) {\n notify.error(\n t('ggnomad.storefront.errorTitle', 'Could not save storefront'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const handleTogglePublish = async () => {\n if (!storefront) return;\n try {\n if (storefront.isPublished) {\n await unpublishStorefront({ variables: { id: storefront.id } });\n notify.success(\n t('ggnomad.storefront.unpublishedTitle', 'Storefront unpublished'),\n t('ggnomad.storefront.unpublishedBody', 'It is no longer visible to the public.')\n );\n } else {\n await publishStorefront({ variables: { id: storefront.id } });\n notify.success(\n t('ggnomad.storefront.publishedTitle', 'Storefront published'),\n t('ggnomad.storefront.publishedBody', 'Your branded page is now publicly reachable.')\n );\n }\n await refetch();\n } catch (err) {\n notify.error(\n t('ggnomad.storefront.errorTitle', 'Could not update storefront'),\n err instanceof Error ? err.message : String(err)\n );\n }\n };\n\n const saving = creating || updating;\n const previewColor = HEX_COLOR_PATTERN.test(primaryColor.trim())\n ? primaryColor.trim()\n : '#1E88E5';\n\n if (!providerId) {\n return (\n <PageShell\n title={t('ggnomad.storefront.title', 'Operator Storefront')}\n subtitle={t('ggnomad.storefront.missingProvider', 'No provider selected.')}\n >\n <PagePurpose icon={<Store className=\"size-4\" />}>\n {t(\n 'ggnomad.storefront.missingProviderHelp',\n 'Open a provider from the Provider Dashboard and choose “Manage storefront”.'\n )}\n </PagePurpose>\n </PageShell>\n );\n }\n\n return (\n <PageShell\n title={t('ggnomad.storefront.title', 'Operator Storefront')}\n titleAccent={t('ggnomad.storefront.title.accent', 'Storefront')}\n subtitle={t(\n 'ggnomad.storefront.subtitle',\n 'White-label branding for your public listing page — logo, color, slug, and about text.'\n )}\n >\n <PagePurpose icon={<Store className=\"size-4\" />}>\n {t(\n 'ggnomad.storefront.purpose',\n 'Configure how travelers see your business when they visit your branded storefront URL. Publish when ready — draft branding stays private until then. Custom domains and a drag-and-drop builder are on the roadmap, not part of this core.'\n )}\n </PagePurpose>\n\n {loading && !hydrated ? (\n <div className=\"flex justify-center py-10\">\n <Spinner />\n </div>\n ) : (\n <div className=\"grid gap-5 lg:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <h2 className=\"mb-4 flex items-center gap-2 text-lg font-medium tracking-tight text-text-primary\">\n <Palette className=\"size-4\" />\n {t('ggnomad.storefront.brandingHeading', 'Branding')}\n </h2>\n <div className=\"space-y-4\">\n <div>\n <label className={labelClass} htmlFor=\"storefront-slug\">\n {t('ggnomad.storefront.slugLabel', 'Public slug')}\n </label>\n <Input\n id=\"storefront-slug\"\n className={fieldClass}\n value={slug}\n onChange={(e) => setSlug(e.target.value.toLowerCase())}\n placeholder=\"my-eco-stays\"\n disabled={saving}\n />\n <p className=\"mt-1 text-xs text-text-secondary\">\n {t(\n 'ggnomad.storefront.slugHelp',\n 'Lowercase letters, digits, hyphens — 3-80 chars.'\n )}\n </p>\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-name\">\n {t('ggnomad.storefront.nameLabel', 'Display name')}\n </label>\n <Input\n id=\"storefront-name\"\n className={fieldClass}\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n placeholder={t('ggnomad.storefront.namePlaceholder', 'Sunset Eco Stays')}\n disabled={saving}\n />\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-logo\">\n {t('ggnomad.storefront.logoLabel', 'Logo URL')}\n </label>\n <Input\n id=\"storefront-logo\"\n className={fieldClass}\n value={logoUrl}\n onChange={(e) => setLogoUrl(e.target.value)}\n placeholder=\"https://example.com/logo.png\"\n disabled={saving}\n />\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-color\">\n {t('ggnomad.storefront.colorLabel', 'Primary color')}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <input\n id=\"storefront-color\"\n type=\"color\"\n className=\"h-9 w-12 rounded border border-border-seam bg-bg-canvas\"\n value={HEX_COLOR_PATTERN.test(primaryColor) ? primaryColor : '#1E88E5'}\n onChange={(e) => setPrimaryColor(e.target.value)}\n disabled={saving}\n />\n <Input\n className={fieldClass}\n value={primaryColor}\n onChange={(e) => setPrimaryColor(e.target.value)}\n placeholder=\"#1E88E5\"\n disabled={saving}\n />\n </div>\n </div>\n <div>\n <label className={labelClass} htmlFor=\"storefront-about\">\n {t('ggnomad.storefront.aboutLabel', 'About text')}\n </label>\n <Textarea\n id=\"storefront-about\"\n className={fieldClass}\n rows={4}\n value={aboutText}\n onChange={(e) => setAboutText(e.target.value)}\n placeholder={t(\n 'ggnomad.storefront.aboutPlaceholder',\n 'Tell travelers what makes your business worth booking.'\n )}\n disabled={saving}\n />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-3 pt-2\">\n <Button onClick={handleSave} disabled={saving}>\n {storefront\n ? t('ggnomad.storefront.saveButton', 'Save changes')\n : t('ggnomad.storefront.createButton', 'Create storefront')}\n </Button>\n {storefront ? (\n <Button\n variant=\"secondary\"\n onClick={handleTogglePublish}\n disabled={publishing || unpublishing}\n >\n {storefront.isPublished\n ? t('ggnomad.storefront.unpublishButton', 'Unpublish')\n : t('ggnomad.storefront.publishButton', 'Publish')}\n </Button>\n ) : null}\n {storefront?.isPublished ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Globe className=\"size-3.5\" />\n {t('ggnomad.storefront.livePathLabel', 'Live at /store/{slug}').replace(\n '{slug}',\n storefront.slug\n )}\n </span>\n ) : null}\n </div>\n </div>\n </GlassCard>\n\n {/* Live preview — the same visual shape ggnomadStorefrontBySlug renders publicly. */}\n <div\n className=\"overflow-hidden rounded-lg border border-border-seam\"\n style={{ borderTopColor: previewColor, borderTopWidth: 4 }}\n >\n <div className=\"p-5\" style={{ background: `${previewColor}14` }}>\n <div className=\"flex items-center gap-3\">\n {logoUrl ? (\n <img\n src={logoUrl}\n alt=\"\"\n className=\"size-12 rounded object-contain\"\n onError={(e) => {\n (e.currentTarget as HTMLImageElement).style.display = 'none';\n }}\n />\n ) : (\n <div\n className=\"flex size-12 items-center justify-center rounded text-lg font-semibold text-white\"\n style={{ background: previewColor }}\n >\n {(displayName || 'S').slice(0, 1).toUpperCase()}\n </div>\n )}\n <div>\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {displayName ||\n t('ggnomad.storefront.previewPlaceholderName', 'Your Storefront')}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {slug\n ? `/store/${slug}`\n : t('ggnomad.storefront.previewSlugPlaceholder', '/store/…')}\n </p>\n </div>\n </div>\n {aboutText ? (\n <p className=\"mt-4 text-sm text-text-primary\">{aboutText}</p>\n ) : (\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.storefront.previewNoAbout',\n 'Add an about text to introduce your business.'\n )}\n </p>\n )}\n <div\n className=\"mt-4 inline-block rounded px-3 py-1.5 text-xs font-medium text-white\"\n style={{ background: previewColor }}\n >\n {t('ggnomad.storefront.previewCta', 'Book with us')}\n </div>\n </div>\n <div className=\"border-t border-border-seam bg-bg-surface p-4 text-xs text-text-secondary\">\n {t(\n 'ggnomad.storefront.previewFooter',\n 'ACTIVE properties, tours, events, and activities from this provider render below this banner on the public page.'\n )}\n </div>\n </div>\n </div>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { PageShell as t } from "./PageShell.js";
3
3
  import { useGGNomad as n } from "../providers/GGNomadProvider.js";
4
4
  import { Leaf as r } from "lucide-react";
5
5
  import { useI18n as i } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
- import { useParams as a } from "react-router-dom";
6
+ import { useParams as a } from "react-router";
7
7
  import { useQuery as o } from "@apollo/client/react";
8
8
  import { GlassCard as s, IllustratedEmptyState as c, Spinner as l } from "@burdenoff/fe-libs/ui";
9
9
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"StorefrontPublicPage.js","names":[],"sources":["../../../src/ggnomad/pages/StorefrontPublicPage.tsx"],"sourcesContent":["import { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Leaf } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, Spinner } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_STOREFRONT_BY_SLUG_QUERY } from '../graphql';\nimport { PageShell } from './PageShell';\nimport { useGGNomad } from '../providers/GGNomadProvider';\n\ntype StorefrontListing = {\n id: string;\n name: string;\n price?: number;\n pricePerNight?: number;\n currency: string;\n images: string[];\n rating?: number | null;\n sustainabilityScore: number;\n};\n\ntype StorefrontPage = {\n storefront: {\n id: string;\n displayName: string;\n logoUrl: string | null;\n primaryColor: string | null;\n aboutText: string | null;\n publishedAt: string | null;\n };\n properties: StorefrontListing[];\n tours: StorefrontListing[];\n events: StorefrontListing[];\n activities: StorefrontListing[];\n};\n\n/**\n * BOFF-4363 — the branded storefront page a traveler sees, backed by the\n * genuinely public `ggnomadStorefrontBySlug` query. Note: this route still\n * renders inside the authenticated app shell today — making it reachable\n * without any login at all is a routing/CDN concern for the app shell, not\n * this MFE (tracked alongside the deferred custom-domain work in BOFF-4363).\n */\nexport function StorefrontPublicPage() {\n const { t } = useI18n();\n const { slug = '' } = useParams();\n const { workspaceId = '' } = useGGNomad();\n\n const { data, loading } = useQuery(\n GGNOMAD_STOREFRONT_BY_SLUG_QUERY as TypedDocumentNode<\n { ggnomadStorefrontBySlug: StorefrontPage | null },\n { workspaceId: string; slug: string }\n >,\n { variables: { workspaceId, slug }, skip: !workspaceId || !slug }\n );\n\n const page = data?.ggnomadStorefrontBySlug ?? null;\n const brandColor = page?.storefront.primaryColor ?? '#1E88E5';\n const allListings = page\n ? [...page.properties, ...page.tours, ...page.events, ...page.activities]\n : [];\n\n if (loading) {\n return (\n <PageShell title={t('ggnomad.storefrontPublic.title', 'Storefront')} subtitle=\"\">\n <div className=\"flex justify-center py-10\">\n <Spinner />\n </div>\n </PageShell>\n );\n }\n\n if (!page) {\n return (\n <PageShell\n title={t('ggnomad.storefrontPublic.title', 'Storefront')}\n subtitle={t(\n 'ggnomad.storefrontPublic.notFoundSubtitle',\n 'This storefront is not available.'\n )}\n >\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={t('ggnomad.storefrontPublic.notFoundTitle', 'Storefront not found')}\n description={t(\n 'ggnomad.storefrontPublic.notFoundDescription',\n 'This link may be mistyped, or the operator has not published a storefront yet.'\n )}\n />\n </PageShell>\n );\n }\n\n return (\n <div>\n <div\n className=\"p-6\"\n style={{ background: `${brandColor}14`, borderBottom: `4px solid ${brandColor}` }}\n >\n <div className=\"mx-auto flex max-w-4xl items-center gap-4\">\n {page.storefront.logoUrl ? (\n <img src={page.storefront.logoUrl} alt=\"\" className=\"size-16 rounded object-contain\" />\n ) : (\n <div\n className=\"flex size-16 items-center justify-center rounded text-2xl font-semibold text-white\"\n style={{ background: brandColor }}\n >\n {page.storefront.displayName.slice(0, 1).toUpperCase()}\n </div>\n )}\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {page.storefront.displayName}\n </h1>\n {page.storefront.aboutText ? (\n <p className=\"mt-1 max-w-2xl text-sm text-text-secondary\">\n {page.storefront.aboutText}\n </p>\n ) : null}\n </div>\n </div>\n </div>\n\n <div className=\"mx-auto max-w-4xl p-6\">\n {allListings.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={t('ggnomad.storefrontPublic.emptyTitle', 'Nothing listed yet')}\n description={t(\n 'ggnomad.storefrontPublic.emptyDescription',\n 'This operator has not published any active listings.'\n )}\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {allListings.map((listing) => (\n <GlassCard key={listing.id} treatment=\"glass\" className=\"border-border-seam p-4\">\n <h3 className=\"font-medium text-text-primary\">{listing.name}</h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {(listing.price ?? listing.pricePerNight ?? 0).toLocaleString(undefined, {\n style: 'currency',\n currency: listing.currency,\n })}\n </p>\n {listing.sustainabilityScore > 0 ? (\n <p className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Leaf className=\"size-3.5 text-emerald-500\" />\n {t(\n 'ggnomad.storefrontPublic.sustainabilityScore',\n '{score}% self-reported sustainable'\n ).replace('{score}', String(listing.sustainabilityScore))}\n </p>\n ) : null}\n </GlassCard>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AA4CA,SAAgB,IAAuB;CACrC,IAAM,EAAE,SAAM,EAAQ,GAChB,EAAE,UAAO,OAAO,EAAU,GAC1B,EAAE,iBAAc,OAAO,EAAW,GAElC,EAAE,SAAM,eAAY,EACxB,GAIA;EAAE,WAAW;GAAE;GAAa;EAAK;EAAG,MAAM,CAAC,KAAe,CAAC;CAAK,CAClE,GAEM,IAAO,GAAM,2BAA2B,MACxC,IAAa,GAAM,WAAW,gBAAgB,WAC9C,IAAc,IAChB;EAAC,GAAG,EAAK;EAAY,GAAG,EAAK;EAAO,GAAG,EAAK;EAAQ,GAAG,EAAK;CAAU,IACtE,CAAC;CAiCL,OA/BI,IAEA,kBAAC,GAAD;EAAW,OAAO,EAAE,kCAAkC,YAAY;EAAG,UAAS;YAC5E,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,CAAU,CAAA;EACP,CAAA;CACI,CAAA,IAIV,IAsBH,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO;GAAE,YAAY,GAAG,EAAW;GAAK,cAAc,aAAa;EAAa;YAEhF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAK,WAAW,UACf,kBAAC,OAAD;IAAK,KAAK,EAAK,WAAW;IAAS,KAAI;IAAG,WAAU;GAAkC,CAAA,IAEtF,kBAAC,OAAD;IACE,WAAU;IACV,OAAO,EAAE,YAAY,EAAW;cAE/B,EAAK,WAAW,YAAY,MAAM,GAAG,CAAC,EAAE,YAAY;GAClD,CAAA,GAEP,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAK,WAAW;GACf,CAAA,GACH,EAAK,WAAW,YACf,kBAAC,KAAD;IAAG,WAAU;cACV,EAAK,WAAW;GAChB,CAAA,IACD,IACD,EAAA,CAAA,CACF;;CACF,CAAA,GAEL,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAY,WAAW,IACtB,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,uCAAuC,oBAAoB;GACpE,aAAa,EACX,6CACA,sDACF;EACD,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,GAAD;IAA4B,WAAU;IAAQ,WAAU;cAAxD;KACE,kBAAC,MAAD;MAAI,WAAU;gBAAiC,EAAQ;KAAS,CAAA;KAChE,kBAAC,KAAD;MAAG,WAAU;iBACT,EAAQ,SAAS,EAAQ,iBAAiB,GAAG,eAAe,KAAA,GAAW;OACvE,OAAO;OACP,UAAU,EAAQ;MACpB,CAAC;KACA,CAAA;KACF,EAAQ,sBAAsB,IAC7B,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACE,kBAAC,GAAD,EAAM,WAAU,4BAA6B,CAAA,GAC5C,EACC,gDACA,oCACF,EAAE,QAAQ,WAAW,OAAO,EAAQ,mBAAmB,CAAC,CACvD;UACD;IACK;MAjBK,EAAQ,EAiBb,CACZ;EACE,CAAA;CAEJ,CAAA,CACF,EAAA,CAAA,IApFH,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC,YAAY;EACvD,UAAU,EACR,6CACA,mCACF;YAEA,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,0CAA0C,sBAAsB;GACzE,aAAa,EACX,gDACA,gFACF;EACD,CAAA;CACQ,CAAA;AAuEjB"}
1
+ {"version":3,"file":"StorefrontPublicPage.js","names":[],"sources":["../../../src/ggnomad/pages/StorefrontPublicPage.tsx"],"sourcesContent":["import { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Leaf } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, Spinner } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_STOREFRONT_BY_SLUG_QUERY } from '../graphql';\nimport { PageShell } from './PageShell';\nimport { useGGNomad } from '../providers/GGNomadProvider';\n\ntype StorefrontListing = {\n id: string;\n name: string;\n price?: number;\n pricePerNight?: number;\n currency: string;\n images: string[];\n rating?: number | null;\n sustainabilityScore: number;\n};\n\ntype StorefrontPage = {\n storefront: {\n id: string;\n displayName: string;\n logoUrl: string | null;\n primaryColor: string | null;\n aboutText: string | null;\n publishedAt: string | null;\n };\n properties: StorefrontListing[];\n tours: StorefrontListing[];\n events: StorefrontListing[];\n activities: StorefrontListing[];\n};\n\n/**\n * BOFF-4363 — the branded storefront page a traveler sees, backed by the\n * genuinely public `ggnomadStorefrontBySlug` query. Note: this route still\n * renders inside the authenticated app shell today — making it reachable\n * without any login at all is a routing/CDN concern for the app shell, not\n * this MFE (tracked alongside the deferred custom-domain work in BOFF-4363).\n */\nexport function StorefrontPublicPage() {\n const { t } = useI18n();\n const { slug = '' } = useParams();\n const { workspaceId = '' } = useGGNomad();\n\n const { data, loading } = useQuery(\n GGNOMAD_STOREFRONT_BY_SLUG_QUERY as TypedDocumentNode<\n { ggnomadStorefrontBySlug: StorefrontPage | null },\n { workspaceId: string; slug: string }\n >,\n { variables: { workspaceId, slug }, skip: !workspaceId || !slug }\n );\n\n const page = data?.ggnomadStorefrontBySlug ?? null;\n const brandColor = page?.storefront.primaryColor ?? '#1E88E5';\n const allListings = page\n ? [...page.properties, ...page.tours, ...page.events, ...page.activities]\n : [];\n\n if (loading) {\n return (\n <PageShell title={t('ggnomad.storefrontPublic.title', 'Storefront')} subtitle=\"\">\n <div className=\"flex justify-center py-10\">\n <Spinner />\n </div>\n </PageShell>\n );\n }\n\n if (!page) {\n return (\n <PageShell\n title={t('ggnomad.storefrontPublic.title', 'Storefront')}\n subtitle={t(\n 'ggnomad.storefrontPublic.notFoundSubtitle',\n 'This storefront is not available.'\n )}\n >\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={t('ggnomad.storefrontPublic.notFoundTitle', 'Storefront not found')}\n description={t(\n 'ggnomad.storefrontPublic.notFoundDescription',\n 'This link may be mistyped, or the operator has not published a storefront yet.'\n )}\n />\n </PageShell>\n );\n }\n\n return (\n <div>\n <div\n className=\"p-6\"\n style={{ background: `${brandColor}14`, borderBottom: `4px solid ${brandColor}` }}\n >\n <div className=\"mx-auto flex max-w-4xl items-center gap-4\">\n {page.storefront.logoUrl ? (\n <img src={page.storefront.logoUrl} alt=\"\" className=\"size-16 rounded object-contain\" />\n ) : (\n <div\n className=\"flex size-16 items-center justify-center rounded text-2xl font-semibold text-white\"\n style={{ background: brandColor }}\n >\n {page.storefront.displayName.slice(0, 1).toUpperCase()}\n </div>\n )}\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {page.storefront.displayName}\n </h1>\n {page.storefront.aboutText ? (\n <p className=\"mt-1 max-w-2xl text-sm text-text-secondary\">\n {page.storefront.aboutText}\n </p>\n ) : null}\n </div>\n </div>\n </div>\n\n <div className=\"mx-auto max-w-4xl p-6\">\n {allListings.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={t('ggnomad.storefrontPublic.emptyTitle', 'Nothing listed yet')}\n description={t(\n 'ggnomad.storefrontPublic.emptyDescription',\n 'This operator has not published any active listings.'\n )}\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {allListings.map((listing) => (\n <GlassCard key={listing.id} treatment=\"glass\" className=\"border-border-seam p-4\">\n <h3 className=\"font-medium text-text-primary\">{listing.name}</h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {(listing.price ?? listing.pricePerNight ?? 0).toLocaleString(undefined, {\n style: 'currency',\n currency: listing.currency,\n })}\n </p>\n {listing.sustainabilityScore > 0 ? (\n <p className=\"mt-2 inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Leaf className=\"size-3.5 text-emerald-500\" />\n {t(\n 'ggnomad.storefrontPublic.sustainabilityScore',\n '{score}% self-reported sustainable'\n ).replace('{score}', String(listing.sustainabilityScore))}\n </p>\n ) : null}\n </GlassCard>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AA4CA,SAAgB,IAAuB;CACrC,IAAM,EAAE,SAAM,EAAQ,GAChB,EAAE,UAAO,OAAO,EAAU,GAC1B,EAAE,iBAAc,OAAO,EAAW,GAElC,EAAE,SAAM,eAAY,EACxB,GAIA;EAAE,WAAW;GAAE;GAAa;EAAK;EAAG,MAAM,CAAC,KAAe,CAAC;CAAK,CAClE,GAEM,IAAO,GAAM,2BAA2B,MACxC,IAAa,GAAM,WAAW,gBAAgB,WAC9C,IAAc,IAChB;EAAC,GAAG,EAAK;EAAY,GAAG,EAAK;EAAO,GAAG,EAAK;EAAQ,GAAG,EAAK;CAAU,IACtE,CAAC;CAiCL,OA/BI,IAEA,kBAAC,GAAD;EAAW,OAAO,EAAE,kCAAkC,YAAY;EAAG,UAAS;YAC5E,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,CAAU,CAAA;EACP,CAAA;CACI,CAAA,IAIV,IAsBH,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO;GAAE,YAAY,GAAG,EAAW;GAAK,cAAc,aAAa;EAAa;YAEhF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAK,WAAW,UACf,kBAAC,OAAD;IAAK,KAAK,EAAK,WAAW;IAAS,KAAI;IAAG,WAAU;GAAkC,CAAA,IAEtF,kBAAC,OAAD;IACE,WAAU;IACV,OAAO,EAAE,YAAY,EAAW;cAE/B,EAAK,WAAW,YAAY,MAAM,GAAG,CAAC,EAAE,YAAY;GAClD,CAAA,GAEP,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAK,WAAW;GACf,CAAA,GACH,EAAK,WAAW,YACf,kBAAC,KAAD;IAAG,WAAU;cACV,EAAK,WAAW;GAChB,CAAA,IACD,IACD,EAAA,CAAA,CACF;;CACF,CAAA,GAEL,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAY,WAAW,IACtB,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,uCAAuC,oBAAoB;GACpE,aAAa,EACX,6CACA,sDACF;EACD,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,GAAD;IAA4B,WAAU;IAAQ,WAAU;cAAxD;KACE,kBAAC,MAAD;MAAI,WAAU;gBAAiC,EAAQ;KAAS,CAAA;KAChE,kBAAC,KAAD;MAAG,WAAU;iBACT,EAAQ,SAAS,EAAQ,iBAAiB,GAAG,eAAe,KAAA,GAAW;OACvE,OAAO;OACP,UAAU,EAAQ;MACpB,CAAC;KACA,CAAA;KACF,EAAQ,sBAAsB,IAC7B,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACE,kBAAC,GAAD,EAAM,WAAU,4BAA6B,CAAA,GAC5C,EACC,gDACA,oCACF,EAAE,QAAQ,WAAW,OAAO,EAAQ,mBAAmB,CAAC,CACvD;UACD;IACK;MAjBK,EAAQ,EAiBb,CACZ;EACE,CAAA;CAEJ,CAAA,CACF,EAAA,CAAA,IApFH,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC,YAAY;EACvD,UAAU,EACR,6CACA,mCACF;YAEA,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,0CAA0C,sBAAsB;GACzE,aAAa,EACX,gDACA,gFACF;EACD,CAAA;CACQ,CAAA;AAuEjB"}
@@ -12,7 +12,7 @@ import "../components/index.js";
12
12
  import { useState as u } from "react";
13
13
  import { CheckCircle2 as d, Compass as f, Pencil as p } from "lucide-react";
14
14
  import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
15
- import { useNavigate as h, useParams as g } from "react-router-dom";
15
+ import { useNavigate as h, useParams as g } from "react-router";
16
16
  import { useQuery as _ } from "@apollo/client/react";
17
17
  import { GlassCard as v, IllustratedEmptyState as y, NextSteps as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
18
18
  import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"TourDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { CheckCircle2, Compass, Pencil } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_TOUR_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { PageShell } from './PageShell';\nimport {\n DetailRow,\n SectionCard,\n DetailHero,\n BookingPanel,\n ReviewsSection,\n ListingEditDialog,\n} from '../components';\n\nexport function TourDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_TOUR_QUERY as TypedDocumentNode<\n {\n ggnomadTour: {\n id: string;\n name: string;\n description?: string;\n duration: string;\n difficulty?: string;\n guideName?: string;\n currency: string;\n price: number;\n status?: string;\n highlights: string[];\n images?: string[];\n } | null;\n },\n { id: string }\n >,\n { variables: { id }, skip: !id }\n );\n const tour = data?.ggnomadTour;\n\n return (\n <PageShell\n title={tour?.name ?? t('ggnomad.tour.fallbackTitle', 'Tour details')}\n subtitle={t('ggnomad.tour.subtitle', 'Tour package details and booking context')}\n >\n {!tour ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.tour.notFoundTitle', 'No tour found')}\n description={t(\n 'ggnomad.tour.notFoundDescription',\n 'This tour is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n <DetailHero image={tour.images?.[0]} alt={tour.name} />\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tour.purpose',\n 'See exactly what this tour involves — duration, difficulty, your guide, price and the highlights you’ll experience — so you can confirm it fits your trip before booking.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-tour-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.tour.next.browse', 'Explore more experiences'),\n description: t(\n 'ggnomad.tour.next.browseDesc',\n 'Return to Tourism to compare tours and activities.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'tourism')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.tour.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.tour.editListing', 'Edit listing')}\n title={t('ggnomad.tour.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow label={t('ggnomad.tour.duration', 'Duration')} value={tour.duration} />\n <DetailRow\n label={t('ggnomad.tour.difficulty', 'Difficulty')}\n value={tour.difficulty ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.guide', 'Guide')}\n value={tour.guideName ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.price', 'Price')}\n value={`${tour.currency} ${Number(tour.price).toFixed(2)}`}\n />\n </dl>\n </GlassCard>\n <SectionCard title={t('ggnomad.tour.highlights', 'Highlights')}>\n <ul className=\"space-y-2 text-sm\">\n {(tour.highlights ?? []).map((highlight) => (\n <li key={highlight} className=\"flex items-start gap-2 text-text-primary\">\n <CheckCircle2\n className=\"mt-0.5 size-4 flex-shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n {highlight}\n </li>\n ))}\n </ul>\n </SectionCard>\n <ReviewsSection targetType=\"TOUR\" targetId={tour.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"TOUR\"\n itemId={tour.id ?? id}\n itemName={tour.name}\n unitPrice={tour.price ?? 0}\n currency={tour.currency ?? 'USD'}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"TOUR\"\n id={tour.id ?? id}\n initial={{\n name: tour.name,\n description: tour.description,\n price: tour.price,\n status: tour.status,\n images: tour.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TourDetailsPage.js","names":[],"sources":["../../../src/ggnomad/pages/TourDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useNavigate, useParams } from 'react-router';\nimport { CheckCircle2, Compass, Pencil } from 'lucide-react';\nimport { GlassCard, IllustratedEmptyState, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { GGNOMAD_TOUR_QUERY } from '../graphql';\nimport { useGGNomad } from '../providers/GGNomadProvider';\nimport { joinPath } from '../utils/navigation';\nimport { PageShell } from './PageShell';\nimport {\n DetailRow,\n SectionCard,\n DetailHero,\n BookingPanel,\n ReviewsSection,\n ListingEditDialog,\n} from '../components';\n\nexport function TourDetailsPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useGGNomad();\n const { id = '' } = useParams();\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const { data, refetch } = useQuery(\n GGNOMAD_TOUR_QUERY as TypedDocumentNode<\n {\n ggnomadTour: {\n id: string;\n name: string;\n description?: string;\n duration: string;\n difficulty?: string;\n guideName?: string;\n currency: string;\n price: number;\n status?: string;\n highlights: string[];\n images?: string[];\n } | null;\n },\n { id: string }\n >,\n { variables: { id }, skip: !id }\n );\n const tour = data?.ggnomadTour;\n\n return (\n <PageShell\n title={tour?.name ?? t('ggnomad.tour.fallbackTitle', 'Tour details')}\n subtitle={t('ggnomad.tour.subtitle', 'Tour package details and booking context')}\n >\n {!tour ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.tour.notFoundTitle', 'No tour found')}\n description={t(\n 'ggnomad.tour.notFoundDescription',\n 'This tour is unavailable or may have been removed.'\n )}\n />\n ) : (\n <>\n <DetailHero image={tour.images?.[0]} alt={tour.name} />\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.tour.purpose',\n 'See exactly what this tour involves — duration, difficulty, your guide, price and the highlights you’ll experience — so you can confirm it fits your trip before booking.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-tour-detail\"\n steps={[\n {\n id: 'browse',\n label: t('ggnomad.tour.next.browse', 'Explore more experiences'),\n description: t(\n 'ggnomad.tour.next.browseDesc',\n 'Return to Tourism to compare tours and activities.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate(joinPath(basePath, 'tourism')),\n },\n ]}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-medium tracking-tight text-text-primary\">\n {t('ggnomad.tour.details', 'Details')}\n </h2>\n <button\n onClick={() => setEditDialogOpen(true)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-action-primary-bg hover:text-action-primary-text\"\n aria-label={t('ggnomad.tour.editListing', 'Edit listing')}\n title={t('ggnomad.tour.editListing', 'Edit listing')}\n >\n <Pencil className=\"size-4\" />\n </button>\n </div>\n <dl className=\"space-y-2 text-sm\">\n <DetailRow label={t('ggnomad.tour.duration', 'Duration')} value={tour.duration} />\n <DetailRow\n label={t('ggnomad.tour.difficulty', 'Difficulty')}\n value={tour.difficulty ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.guide', 'Guide')}\n value={tour.guideName ?? t('ggnomad.tour.na', 'N/A')}\n />\n <DetailRow\n label={t('ggnomad.tour.price', 'Price')}\n value={`${tour.currency} ${Number(tour.price).toFixed(2)}`}\n />\n </dl>\n </GlassCard>\n <SectionCard title={t('ggnomad.tour.highlights', 'Highlights')}>\n <ul className=\"space-y-2 text-sm\">\n {(tour.highlights ?? []).map((highlight) => (\n <li key={highlight} className=\"flex items-start gap-2 text-text-primary\">\n <CheckCircle2\n className=\"mt-0.5 size-4 flex-shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n {highlight}\n </li>\n ))}\n </ul>\n </SectionCard>\n <ReviewsSection targetType=\"TOUR\" targetId={tour.id ?? id} />\n </div>\n <div>\n <BookingPanel\n bookingType=\"TOUR\"\n itemId={tour.id ?? id}\n itemName={tour.name}\n unitPrice={tour.price ?? 0}\n currency={tour.currency ?? 'USD'}\n />\n </div>\n </div>\n\n <ListingEditDialog\n open={editDialogOpen}\n onOpenChange={setEditDialogOpen}\n targetType=\"TOUR\"\n id={tour.id ?? id}\n initial={{\n name: tour.name,\n description: tour.description,\n price: tour.price,\n status: tour.status,\n images: tour.images,\n }}\n onSaved={() => refetch()}\n />\n </>\n )}\n </PageShell>\n );\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ import { notify as l } from "../utils/notify.js";
6
6
  import { useState as u } from "react";
7
7
  import { ChevronDown as d, Plus as re, Users as ie, X as ae } from "lucide-react";
8
8
  import { useI18n as oe } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
9
- import { useNavigate as f, useParams as p } from "react-router-dom";
9
+ import { useNavigate as f, useParams as p } from "react-router";
10
10
  import { useMutation as m, useQuery as h } from "@apollo/client/react";
11
11
  import { AlertDialog as g, AlertDialogAction as _, AlertDialogCancel as v, AlertDialogContent as y, AlertDialogDescription as b, AlertDialogFooter as x, AlertDialogHeader as S, AlertDialogTitle as C, GlassCard as w, IllustratedEmptyState as se, Tabs as ce, TabsContent as T, TabsList as E, TabsTrigger as D } from "@burdenoff/fe-libs/ui";
12
12
  import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";