@apteva/integrations 0.3.62 → 0.15.4
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.
- package/dist/aws-sigv4.d.ts +32 -0
- package/dist/aws-sigv4.d.ts.map +1 -0
- package/dist/aws-sigv4.js +126 -0
- package/dist/aws-sigv4.js.map +1 -0
- package/dist/explorer/main.js +21617 -0
- package/dist/explorer/main.js.map +90 -0
- package/dist/explorer/style.css +2 -0
- package/dist/http-executor.d.ts.map +1 -1
- package/dist/http-executor.js +180 -12
- package/dist/http-executor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-generator.d.ts +7 -2
- package/dist/mcp-generator.d.ts.map +1 -1
- package/dist/mcp-generator.js +46 -5
- package/dist/mcp-generator.js.map +1 -1
- package/dist/oauth.js +1 -1
- package/dist/oauth.js.map +1 -1
- package/dist/types.d.ts +251 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/github/ActivityFeed.d.ts +24 -0
- package/dist/ui/github/ActivityFeed.d.ts.map +1 -0
- package/dist/ui/github/ActivityFeed.js +106 -0
- package/dist/ui/github/ActivityFeed.js.map +1 -0
- package/dist/ui/github/ActivityFeed.mjs +3 -0
- package/dist/ui/github/ActivityFeed.mjs.map +29 -0
- package/dist/ui/github/CommitCard.d.ts +24 -0
- package/dist/ui/github/CommitCard.d.ts.map +1 -0
- package/dist/ui/github/CommitCard.js +102 -0
- package/dist/ui/github/CommitCard.js.map +1 -0
- package/dist/ui/github/CommitCard.mjs +5 -0
- package/dist/ui/github/CommitCard.mjs.map +11 -0
- package/dist/ui/github/IssueCard.d.ts +33 -0
- package/dist/ui/github/IssueCard.d.ts.map +1 -0
- package/dist/ui/github/IssueCard.js +131 -0
- package/dist/ui/github/IssueCard.js.map +1 -0
- package/dist/ui/github/IssueCard.mjs +3 -0
- package/dist/ui/github/IssueCard.mjs.map +21 -0
- package/dist/ui/github/PullRequestCard.d.ts +36 -0
- package/dist/ui/github/PullRequestCard.d.ts.map +1 -0
- package/dist/ui/github/PullRequestCard.js +158 -0
- package/dist/ui/github/PullRequestCard.js.map +1 -0
- package/dist/ui/github/PullRequestCard.mjs +3 -0
- package/dist/ui/github/PullRequestCard.mjs.map +22 -0
- package/dist/ui/github/WorkflowRunCard.d.ts +30 -0
- package/dist/ui/github/WorkflowRunCard.d.ts.map +1 -0
- package/dist/ui/github/WorkflowRunCard.js +124 -0
- package/dist/ui/github/WorkflowRunCard.js.map +1 -0
- package/dist/ui/github/WorkflowRunCard.mjs +3 -0
- package/dist/ui/github/WorkflowRunCard.mjs.map +11 -0
- package/dist/ui/github/lib/github.d.ts +43 -0
- package/dist/ui/github/lib/github.d.ts.map +1 -0
- package/dist/ui/github/lib/github.js +151 -0
- package/dist/ui/github/lib/github.js.map +1 -0
- package/dist/ui/hubspot/ActivityFeed.d.ts +22 -0
- package/dist/ui/hubspot/ActivityFeed.d.ts.map +1 -0
- package/dist/ui/hubspot/ActivityFeed.js +52 -0
- package/dist/ui/hubspot/ActivityFeed.js.map +1 -0
- package/dist/ui/hubspot/ActivityFeed.mjs +3 -0
- package/dist/ui/hubspot/ActivityFeed.mjs.map +26 -0
- package/dist/ui/hubspot/CompanyCard.d.ts +22 -0
- package/dist/ui/hubspot/CompanyCard.d.ts.map +1 -0
- package/dist/ui/hubspot/CompanyCard.js +63 -0
- package/dist/ui/hubspot/CompanyCard.js.map +1 -0
- package/dist/ui/hubspot/CompanyCard.mjs +3 -0
- package/dist/ui/hubspot/CompanyCard.mjs.map +11 -0
- package/dist/ui/hubspot/ContactCard.d.ts +22 -0
- package/dist/ui/hubspot/ContactCard.d.ts.map +1 -0
- package/dist/ui/hubspot/ContactCard.js +62 -0
- package/dist/ui/hubspot/ContactCard.js.map +1 -0
- package/dist/ui/hubspot/ContactCard.mjs +3 -0
- package/dist/ui/hubspot/ContactCard.mjs.map +11 -0
- package/dist/ui/hubspot/ContactList.d.ts +21 -0
- package/dist/ui/hubspot/ContactList.d.ts.map +1 -0
- package/dist/ui/hubspot/ContactList.js +31 -0
- package/dist/ui/hubspot/ContactList.js.map +1 -0
- package/dist/ui/hubspot/ContactList.mjs +3 -0
- package/dist/ui/hubspot/ContactList.mjs.map +11 -0
- package/dist/ui/hubspot/DealCard.d.ts +23 -0
- package/dist/ui/hubspot/DealCard.d.ts.map +1 -0
- package/dist/ui/hubspot/DealCard.js +63 -0
- package/dist/ui/hubspot/DealCard.js.map +1 -0
- package/dist/ui/hubspot/DealCard.mjs +3 -0
- package/dist/ui/hubspot/DealCard.mjs.map +11 -0
- package/dist/ui/hubspot/DealList.d.ts +24 -0
- package/dist/ui/hubspot/DealList.d.ts.map +1 -0
- package/dist/ui/hubspot/DealList.js +35 -0
- package/dist/ui/hubspot/DealList.js.map +1 -0
- package/dist/ui/hubspot/DealList.mjs +3 -0
- package/dist/ui/hubspot/DealList.mjs.map +11 -0
- package/dist/ui/hubspot/EmailCard.d.ts +25 -0
- package/dist/ui/hubspot/EmailCard.d.ts.map +1 -0
- package/dist/ui/hubspot/EmailCard.js +62 -0
- package/dist/ui/hubspot/EmailCard.js.map +1 -0
- package/dist/ui/hubspot/EmailCard.mjs +5 -0
- package/dist/ui/hubspot/EmailCard.mjs.map +11 -0
- package/dist/ui/hubspot/InboxStrip.d.ts +23 -0
- package/dist/ui/hubspot/InboxStrip.d.ts.map +1 -0
- package/dist/ui/hubspot/InboxStrip.js +36 -0
- package/dist/ui/hubspot/InboxStrip.js.map +1 -0
- package/dist/ui/hubspot/InboxStrip.mjs +3 -0
- package/dist/ui/hubspot/InboxStrip.mjs.map +11 -0
- package/dist/ui/hubspot/PipelineStrip.d.ts +22 -0
- package/dist/ui/hubspot/PipelineStrip.d.ts.map +1 -0
- package/dist/ui/hubspot/PipelineStrip.js +54 -0
- package/dist/ui/hubspot/PipelineStrip.js.map +1 -0
- package/dist/ui/hubspot/PipelineStrip.mjs +3 -0
- package/dist/ui/hubspot/PipelineStrip.mjs.map +11 -0
- package/dist/ui/hubspot/TicketCard.d.ts +25 -0
- package/dist/ui/hubspot/TicketCard.d.ts.map +1 -0
- package/dist/ui/hubspot/TicketCard.js +53 -0
- package/dist/ui/hubspot/TicketCard.js.map +1 -0
- package/dist/ui/hubspot/TicketCard.mjs +3 -0
- package/dist/ui/hubspot/TicketCard.mjs.map +21 -0
- package/dist/ui/hubspot/TicketList.d.ts +21 -0
- package/dist/ui/hubspot/TicketList.d.ts.map +1 -0
- package/dist/ui/hubspot/TicketList.js +33 -0
- package/dist/ui/hubspot/TicketList.js.map +1 -0
- package/dist/ui/hubspot/TicketList.mjs +3 -0
- package/dist/ui/hubspot/TicketList.mjs.map +11 -0
- package/dist/ui/hubspot/lib/hubspot.d.ts +24 -0
- package/dist/ui/hubspot/lib/hubspot.d.ts.map +1 -0
- package/dist/ui/hubspot/lib/hubspot.js +176 -0
- package/dist/ui/hubspot/lib/hubspot.js.map +1 -0
- package/dist/ui/notion/DatabaseCard.d.ts +24 -0
- package/dist/ui/notion/DatabaseCard.d.ts.map +1 -0
- package/dist/ui/notion/DatabaseCard.js +86 -0
- package/dist/ui/notion/DatabaseCard.js.map +1 -0
- package/dist/ui/notion/DatabaseCard.mjs +3 -0
- package/dist/ui/notion/DatabaseCard.mjs.map +11 -0
- package/dist/ui/notion/DatabaseRowList.d.ts +36 -0
- package/dist/ui/notion/DatabaseRowList.d.ts.map +1 -0
- package/dist/ui/notion/DatabaseRowList.js +87 -0
- package/dist/ui/notion/DatabaseRowList.js.map +1 -0
- package/dist/ui/notion/DatabaseRowList.mjs +3 -0
- package/dist/ui/notion/DatabaseRowList.mjs.map +11 -0
- package/dist/ui/notion/PageCard.d.ts +27 -0
- package/dist/ui/notion/PageCard.d.ts.map +1 -0
- package/dist/ui/notion/PageCard.js +80 -0
- package/dist/ui/notion/PageCard.js.map +1 -0
- package/dist/ui/notion/PageCard.mjs +3 -0
- package/dist/ui/notion/PageCard.mjs.map +11 -0
- package/dist/ui/notion/PageList.d.ts +24 -0
- package/dist/ui/notion/PageList.d.ts.map +1 -0
- package/dist/ui/notion/PageList.js +51 -0
- package/dist/ui/notion/PageList.js.map +1 -0
- package/dist/ui/notion/PageList.mjs +3 -0
- package/dist/ui/notion/PageList.mjs.map +11 -0
- package/dist/ui/notion/lib/notion.d.ts +35 -0
- package/dist/ui/notion/lib/notion.d.ts.map +1 -0
- package/dist/ui/notion/lib/notion.js +119 -0
- package/dist/ui/notion/lib/notion.js.map +1 -0
- package/dist/xml-to-json.d.ts +20 -0
- package/dist/xml-to-json.d.ts.map +1 -0
- package/dist/xml-to-json.js +256 -0
- package/dist/xml-to-json.js.map +1 -0
- package/package.json +13 -1
- package/src/apps/adroll.json +254 -0
- package/src/apps/ahrefs.json +156 -0
- package/src/apps/airtable.json +4 -13
- package/src/apps/algolia.json +115 -0
- package/src/apps/alibaba-cloud.json +211 -0
- package/src/apps/aliexpress.json +369 -0
- package/src/apps/alpaca-market-data.json +699 -0
- package/src/apps/alpaca-trading.json +214 -989
- package/src/apps/amazon-ads.json +249 -0
- package/src/apps/amazon-associates.json +102 -0
- package/src/apps/amplitude.json +86 -0
- package/src/apps/anchor-browser.json +173 -0
- package/src/apps/anthropic-api.json +9 -4
- package/src/apps/api-sports.json +180 -0
- package/src/apps/apple-search-ads.json +266 -0
- package/src/apps/auth0.json +126 -0
- package/src/apps/awin.json +111 -0
- package/src/apps/aws-codebuild.json +139 -0
- package/src/apps/aws-mediaconvert.json +196 -0
- package/src/apps/aws-s3.json +108 -192
- package/src/apps/aws-ses.json +666 -303
- package/src/apps/aws-sns.json +128 -106
- package/src/apps/azure-container-apps.json +116 -0
- package/src/apps/backblaze-b2.json +175 -0
- package/src/apps/bamboohr.json +303 -0
- package/src/apps/basiq.json +308 -0
- package/src/apps/bigcommerce.json +366 -0
- package/src/apps/bigquery.json +121 -0
- package/src/apps/binance-trading.json +7 -4
- package/src/apps/bing-webmaster-tools.json +158 -0
- package/src/apps/bitbucket.json +163 -0
- package/src/apps/blacksmith.json +81 -0
- package/src/apps/bls.json +104 -0
- package/src/apps/bluesky.json +74 -0
- package/src/apps/braze.json +103 -0
- package/src/apps/brevo.json +4 -1
- package/src/apps/brightdata.json +94 -0
- package/src/apps/browserbase.json +237 -0
- package/src/apps/bscscan.json +150 -0
- package/src/apps/buffer.json +121 -0
- package/src/apps/buildjet.json +80 -0
- package/src/apps/builtwith.json +101 -0
- package/src/apps/bunny-cdn.json +104 -0
- package/src/apps/bunny-stream.json +205 -3
- package/src/apps/byrd.json +585 -0
- package/src/apps/calendly.json +10 -7
- package/src/apps/campaign-manager-360.json +264 -0
- package/src/apps/capturekit.json +51 -0
- package/src/apps/circleci.json +212 -0
- package/src/apps/cirrus-runners.json +75 -0
- package/src/apps/cj-affiliate.json +101 -0
- package/src/apps/cjdropshipping.json +278 -0
- package/src/apps/clerk.json +153 -0
- package/src/apps/cloudflare-containers.json +98 -0
- package/src/apps/cloudflare-r2.json +180 -0
- package/src/apps/cloudflare.json +474 -157
- package/src/apps/cloudinary.json +119 -97
- package/src/apps/coconut.json +94 -0
- package/src/apps/contentful.json +157 -0
- package/src/apps/criteo.json +222 -0
- package/src/apps/crunchbase.json +104 -0
- package/src/apps/customer-io.json +106 -0
- package/src/apps/databricks.json +94 -0
- package/src/apps/deepgram.json +3 -0
- package/src/apps/deepl.json +113 -0
- package/src/apps/deepseek.json +5 -2
- package/src/apps/depot.json +102 -0
- package/src/apps/digitalocean-spaces.json +121 -0
- package/src/apps/digitalocean.json +115 -0
- package/src/apps/discord.json +90 -1
- package/src/apps/docker-build-cloud.json +68 -0
- package/src/apps/duffel.json +193 -77
- package/src/apps/dux-soup.json +4 -1
- package/src/apps/dv360.json +287 -0
- package/src/apps/earthly-cloud.json +84 -0
- package/src/apps/eia.json +121 -0
- package/src/apps/elasticsearch.json +282 -0
- package/src/apps/elevenlabs.json +336 -192
- package/src/apps/etherscan.json +162 -0
- package/src/apps/etsy.json +484 -0
- package/src/apps/eventbrite-events.json +5 -2
- package/src/apps/exa.json +101 -0
- package/src/apps/facebook-ads.json +3 -3
- package/src/apps/facebook-api.json +1484 -37
- package/src/apps/finnhub.json +232 -0
- package/src/apps/flightapi.json +248 -0
- package/src/apps/fly-io.json +134 -0
- package/src/apps/fred.json +156 -0
- package/src/apps/gdelt.json +96 -0
- package/src/apps/gelato.json +123 -0
- package/src/apps/gemini.json +143 -49
- package/src/apps/getscreenshot.json +52 -0
- package/src/apps/github.json +355 -39
- package/src/apps/gmail.json +151 -2
- package/src/apps/gnews.json +71 -0
- package/src/apps/google-analytics.json +311 -0
- package/src/apps/google-cloud-storage.json +484 -0
- package/src/apps/google-docs.json +2 -2
- package/src/apps/google-drive.json +2 -2
- package/src/apps/google-places.json +127 -0
- package/src/apps/google-search-console.json +126 -0
- package/src/apps/google-sheets.json +2 -2
- package/src/apps/grafana-cloud.json +98 -0
- package/src/apps/groq.json +119 -0
- package/src/apps/hetzner-object-storage.json +177 -0
- package/src/apps/hetzner.json +255 -367
- package/src/apps/heygen.json +828 -141
- package/src/apps/hive-fulfillment.json +559 -0
- package/src/apps/hotjar.json +91 -0
- package/src/apps/huawei-cloud.json +189 -0
- package/src/apps/huboo.json +286 -0
- package/src/apps/hubspot.json +253 -637
- package/src/apps/huggingface.json +5 -2
- package/src/apps/hunter.json +5 -2
- package/src/apps/hyperbrowser.json +205 -0
- package/src/apps/idrive-e2.json +128 -0
- package/src/apps/impact.json +106 -0
- package/src/apps/instagram-api.json +185 -11
- package/src/apps/instantly.json +169 -0
- package/src/apps/ionos.json +250 -0
- package/src/apps/{learning-platform.json → kalio.json} +162 -3
- package/src/apps/kalshi.json +144 -0
- package/src/apps/keywords-everywhere.json +86 -0
- package/src/apps/kickbox.json +71 -0
- package/src/apps/launchdarkly.json +111 -0
- package/src/apps/leadbyte.json +600 -0
- package/src/apps/leadfeeder.json +89 -0
- package/src/apps/lemlist.json +109 -0
- package/src/apps/linkedin-ads.json +279 -0
- package/src/apps/linkedin.json +96 -2
- package/src/apps/linode-object-storage.json +183 -0
- package/src/apps/linode.json +160 -0
- package/src/apps/lnk-bio.json +5 -2
- package/src/apps/loom.json +5 -2
- package/src/apps/lusha.json +104 -0
- package/src/apps/magalu-cloud.json +187 -0
- package/src/apps/majestic.json +117 -0
- package/src/apps/manifold-markets.json +144 -0
- package/src/apps/mapbox.json +118 -0
- package/src/apps/microsoft-ads.json +246 -0
- package/src/apps/microsoft-onedrive.json +380 -0
- package/src/apps/microsoft-teams.json +315 -96
- package/src/apps/millionverifier.json +85 -0
- package/src/apps/mindee.json +246 -0
- package/src/apps/miro.json +138 -0
- package/src/apps/mistral.json +129 -0
- package/src/apps/mixpanel.json +95 -0
- package/src/apps/moz.json +127 -0
- package/src/apps/mux.json +201 -0
- package/src/apps/namecheap.json +321 -123
- package/src/apps/namespace-cloud.json +84 -0
- package/src/apps/naver-cloud.json +184 -0
- package/src/apps/neon.json +122 -0
- package/src/apps/netlify.json +124 -0
- package/src/apps/neverbounce.json +92 -0
- package/src/apps/newrelic.json +80 -0
- package/src/apps/newsapi.json +86 -0
- package/src/apps/ngrok.json +29 -0
- package/src/apps/nixbuild.json +116 -0
- package/src/apps/northflank.json +161 -0
- package/src/apps/notion.json +3 -0
- package/src/apps/okta.json +131 -0
- package/src/apps/omnikit-analytics.json +73 -1
- package/src/apps/omnikit-api-gateway.json +74 -2
- package/src/apps/omnikit-billing.json +73 -1
- package/src/apps/omnikit-cms.json +73 -1
- package/src/apps/omnikit-code-ops.json +76 -4
- package/src/apps/omnikit-functions.json +74 -2
- package/src/apps/omnikit-intelligence.json +176 -33
- package/src/apps/omnikit-management.json +73 -1
- package/src/apps/omnikit-media.json +73 -1
- package/src/apps/omnikit-messaging.json +72 -0
- package/src/apps/omnikit-redirects.json +73 -1
- package/src/apps/omnikit-sites.json +325 -66
- package/src/apps/omnikit-storage.json +104 -7
- package/src/apps/omnikit-webhooks.json +73 -1
- package/src/apps/omnikit-workflows.json +73 -1
- package/src/apps/onesignal.json +108 -0
- package/src/apps/openai-api.json +176 -30
- package/src/apps/openai-codex.json +187 -0
- package/src/apps/opencode-go.json +113 -0
- package/src/apps/optinmonster.json +7 -4
- package/src/apps/outlook-calendar.json +350 -0
- package/src/apps/outlook-mail.json +337 -0
- package/src/apps/outscraper.json +118 -0
- package/src/apps/ovhcloud.json +209 -0
- package/src/apps/paddle.json +170 -0
- package/src/apps/pagerduty.json +151 -0
- package/src/apps/partnerstack.json +118 -0
- package/src/apps/perplexity.json +37 -0
- package/src/apps/phantombuster.json +85 -0
- package/src/apps/pinecone.json +129 -0
- package/src/apps/pinterest-ads.json +261 -0
- package/src/apps/pinterest.json +217 -0
- package/src/apps/planetscale.json +139 -0
- package/src/apps/polygonscan.json +157 -0
- package/src/apps/polymarket-clob.json +184 -0
- package/src/apps/polymarket-data.json +153 -0
- package/src/apps/porkbun.json +609 -145
- package/src/apps/posthog.json +107 -0
- package/src/apps/pushover.json +28 -0
- package/src/apps/quora-ads.json +251 -0
- package/src/apps/railway.json +57 -0
- package/src/apps/reddit-ads.json +238 -0
- package/src/apps/reddit.json +274 -0
- package/src/apps/render.json +124 -0
- package/src/apps/replicate.json +5 -2
- package/src/apps/reply-io.json +111 -0
- package/src/apps/resend.json +110 -0
- package/src/apps/ringover.json +1144 -0
- package/src/apps/rocketreach.json +158 -0
- package/src/apps/rollbar.json +88 -0
- package/src/apps/runs-on.json +70 -0
- package/src/apps/sanity.json +89 -0
- package/src/apps/scaleway-object-storage.json +175 -0
- package/src/apps/scrapingbee.json +75 -0
- package/src/apps/screenshotlayer.json +49 -0
- package/src/apps/screenshotmachine.json +49 -0
- package/src/apps/se-ranking.json +239 -0
- package/src/apps/seamless-ai.json +91 -0
- package/src/apps/sec-edgar.json +107 -0
- package/src/apps/segment.json +104 -0
- package/src/apps/semrush.json +153 -0
- package/src/apps/sentry.json +109 -0
- package/src/apps/serpapi.json +95 -0
- package/src/apps/serper.json +139 -0
- package/src/apps/shareasale.json +130 -0
- package/src/apps/skimlinks.json +48 -0
- package/src/apps/slack.json +101 -0
- package/src/apps/smartlead.json +146 -0
- package/src/apps/snapchat-ads.json +238 -0
- package/src/apps/snaprender.json +64 -0
- package/src/apps/snowflake.json +70 -0
- package/src/apps/snyk.json +108 -0
- package/src/apps/socialcast.json +74 -8
- package/src/apps/sovrn.json +125 -0
- package/src/apps/spotify-ads.json +231 -0
- package/src/apps/steel.json +239 -0
- package/src/apps/stocktwits.json +120 -0
- package/src/apps/stripe.json +153 -0
- package/src/apps/target-circle.json +348 -0
- package/src/apps/tavily.json +104 -0
- package/src/apps/tavus.json +403 -0
- package/src/apps/telegram.json +5 -2
- package/src/apps/teller.json +187 -0
- package/src/apps/tencent-cloud.json +214 -0
- package/src/apps/tennis-abstract.json +108 -0
- package/src/apps/the-odds-api.json +132 -0
- package/src/apps/the-sports-db.json +163 -0
- package/src/apps/tiktok-ads.json +295 -0
- package/src/apps/tiktok-api.json +181 -7
- package/src/apps/together.json +5 -2
- package/src/apps/trade-desk.json +237 -0
- package/src/apps/trading212.json +26 -29
- package/src/apps/transloadit.json +138 -0
- package/src/apps/truelayer.json +318 -0
- package/src/apps/twilio.json +313 -42
- package/src/apps/twitter-api.json +216 -33
- package/src/apps/ubicloud.json +82 -0
- package/src/apps/uplead.json +105 -0
- package/src/apps/upstash.json +90 -0
- package/src/apps/valueserp.json +63 -0
- package/src/apps/venice-ai.json +685 -0
- package/src/apps/vercel.json +137 -0
- package/src/apps/wappalyzer.json +65 -0
- package/src/apps/wasabi.json +175 -0
- package/src/apps/whale-alert.json +74 -0
- package/src/apps/whatsapp-business.json +131 -0
- package/src/apps/wikipedia.json +112 -0
- package/src/apps/workos.json +123 -0
- package/src/apps/yahoo-dsp.json +265 -0
- package/src/apps/yahoo-finance.json +60 -0
- package/src/apps/youtube-api.json +520 -142
- package/src/apps/zenrows.json +47 -0
- package/src/apps/zenserp.json +99 -0
- package/src/apps/zerobounce.json +80 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// ContactCard — single HubSpot contact. Avatar (Gravatar from email
|
|
2
|
+
// or monogram fallback) + identity, lifecycle pill, last-engagement
|
|
3
|
+
// hint. The card the email-monitor demo wants when the agent is
|
|
4
|
+
// reasoning about a person rather than a deal.
|
|
5
|
+
import { Card, CardHeader, StatusPill, Avatar, DataList } from "@apteva/ui-kit";
|
|
6
|
+
import { lifecycleMeta, recordUrl, pillToDot, timeAgo, minusHoursISO, hubspotVendor } from "./lib/hubspot";
|
|
7
|
+
const previewSample = {
|
|
8
|
+
contact_id: "501",
|
|
9
|
+
firstname: "Sarah",
|
|
10
|
+
lastname: "Chen",
|
|
11
|
+
email: "sarah.chen@acme-logistics.com",
|
|
12
|
+
phone: "+1 312 555 0142",
|
|
13
|
+
jobtitle: "VP Operations",
|
|
14
|
+
lifecyclestage: "customer",
|
|
15
|
+
company_name: "Acme Logistics",
|
|
16
|
+
company_domain: "acme-logistics.com",
|
|
17
|
+
last_engagement_at: minusHoursISO(72),
|
|
18
|
+
last_engagement_kind: "email",
|
|
19
|
+
portal_id: "0",
|
|
20
|
+
};
|
|
21
|
+
function gravatarFor(email) {
|
|
22
|
+
if (!email)
|
|
23
|
+
return undefined;
|
|
24
|
+
// Use Gravatar identicon fallback — no MD5 needed if we accept the
|
|
25
|
+
// Google s2 favicon trick won't work for emails. Skip rather than
|
|
26
|
+
// ship a hash impl in v1; Avatar component will monogram.
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
export default function ContactCard(props) {
|
|
30
|
+
const p = props.preview ? { ...previewSample, ...props } : props;
|
|
31
|
+
const lifecycle = lifecycleMeta(p.lifecyclestage);
|
|
32
|
+
const url = recordUrl("contact", p.contact_id, p.portal_id);
|
|
33
|
+
const fullName = [p.firstname, p.lastname].filter(Boolean).join(" ") || p.email || `Contact ${p.contact_id}`;
|
|
34
|
+
return (<Card>
|
|
35
|
+
<CardHeader vendor={hubspotVendor} title={fullName} subtitle={p.jobtitle || p.email} status={{ label: lifecycle.label, variant: pillToDot(lifecycle.variant) }} action={{ label: "View in HubSpot", href: url }}/>
|
|
36
|
+
<div className="px-3 py-3 flex flex-col gap-3">
|
|
37
|
+
<div className="flex items-center gap-3">
|
|
38
|
+
<Avatar src={gravatarFor(p.email)} name={fullName} size={32}/>
|
|
39
|
+
<div className="min-w-0 flex-1">
|
|
40
|
+
<div className="text-text font-medium truncate">{fullName}</div>
|
|
41
|
+
{p.jobtitle && p.company_name && (<div className="text-text-dim text-xs truncate">
|
|
42
|
+
{p.jobtitle} · {p.company_name}
|
|
43
|
+
</div>)}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<DataList items={[
|
|
48
|
+
...(p.email ? [{ label: "Email", value: <a href={`mailto:${p.email}`} className="text-accent hover:underline">{p.email}</a> }] : []),
|
|
49
|
+
...(p.phone ? [{ label: "Phone", value: <span className="tabular-nums">{p.phone}</span> }] : []),
|
|
50
|
+
{ label: "Lifecycle", value: <StatusPill variant={lifecycle.variant}>{lifecycle.label}</StatusPill> },
|
|
51
|
+
...(p.last_engagement_at ? [{
|
|
52
|
+
label: "Last contact",
|
|
53
|
+
value: (<span>
|
|
54
|
+
<span className="text-text">{p.last_engagement_kind || "engagement"}</span>
|
|
55
|
+
<span className="text-text-dim"> · {timeAgo(p.last_engagement_at)}</span>
|
|
56
|
+
</span>),
|
|
57
|
+
}] : []),
|
|
58
|
+
]}/>
|
|
59
|
+
</div>
|
|
60
|
+
</Card>);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=ContactCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContactCard.js","sourceRoot":"","sources":["../../../src/ui/hubspot/ContactCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Card as R,CardHeader as b,StatusPill as E,Avatar as O,DataList as _}from"@apteva/ui-kit";import{jsx as M,jsxs as g}from"react/jsx-runtime";var H={subscriber:{label:"Subscriber",variant:"neutral"},lead:{label:"Lead",variant:"neutral"},marketingqualifiedlead:{label:"MQL",variant:"info"},salesqualifiedlead:{label:"SQL",variant:"info"},opportunity:{label:"Opportunity",variant:"info"},customer:{label:"Customer",variant:"success"},evangelist:{label:"Evangelist",variant:"success"},other:{label:"Other",variant:"neutral"}};function G(J){if(!J)return{label:"—",variant:"neutral"};return H[J]??{label:J,variant:"neutral"}}function U(J){if(!J)return"—";let q=new Date(J);if(Number.isNaN(q.getTime()))return J;let Q=Math.round((Date.now()-q.getTime())/1000);if(Q<60)return"just now";let $=Math.round(Q/60);if($<60)return`${$}m ago`;let X=Math.round($/60);if(X<24)return`${X}h ago`;let V=Math.round(X/24);if(V<7)return`${V}d ago`;let z=Math.round(V/7);if(z<5)return`${z}w ago`;return q.toLocaleDateString("en-US",{month:"short",day:"numeric"})}function Y(J){let q=new Date;return q.setHours(q.getHours()-J),q.toISOString()}var K="0";function B(J,q,Q){return`https://app.hubspot.com/contacts/${Q||K}/${J}/${q}`}function D(J){switch(J){case"success":return"live";case"info":return"active";case"warn":return"warn";case"error":return"error";default:return"muted"}}var N=g("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:[M("circle",{cx:"18",cy:"6",r:"2.2"}),M("circle",{cx:"18",cy:"18",r:"2.2"}),M("circle",{cx:"6",cy:"12",r:"2.2"}),M("circle",{cx:"14",cy:"12",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.5"}),M("path",{d:"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8",stroke:"currentColor",strokeWidth:"1.2",fill:"none"})]}),P="#FF7A59",F={name:"HubSpot",logo:N,color:P};import{jsx as W,jsxs as Z}from"react/jsx-runtime";var f={contact_id:"501",firstname:"Sarah",lastname:"Chen",email:"sarah.chen@acme-logistics.com",phone:"+1 312 555 0142",jobtitle:"VP Operations",lifecyclestage:"customer",company_name:"Acme Logistics",company_domain:"acme-logistics.com",last_engagement_at:Y(72),last_engagement_kind:"email",portal_id:"0"};function C(J){if(!J)return;return}function k(J){let q=J.preview?{...f,...J}:J,Q=G(q.lifecyclestage),$=B("contact",q.contact_id,q.portal_id),X=[q.firstname,q.lastname].filter(Boolean).join(" ")||q.email||`Contact ${q.contact_id}`;return Z(R,{children:[W(b,{vendor:F,title:X,subtitle:q.jobtitle||q.email,status:{label:Q.label,variant:D(Q.variant)},action:{label:"View in HubSpot",href:$}}),Z("div",{className:"px-3 py-3 flex flex-col gap-3",children:[Z("div",{className:"flex items-center gap-3",children:[W(O,{src:C(q.email),name:X,size:32}),Z("div",{className:"min-w-0 flex-1",children:[W("div",{className:"text-text font-medium truncate",children:X}),q.jobtitle&&q.company_name&&Z("div",{className:"text-text-dim text-xs truncate",children:[q.jobtitle," · ",q.company_name]})]})]}),W(_,{items:[...q.email?[{label:"Email",value:W("a",{href:`mailto:${q.email}`,className:"text-accent hover:underline",children:q.email})}]:[],...q.phone?[{label:"Phone",value:W("span",{className:"tabular-nums",children:q.phone})}]:[],{label:"Lifecycle",value:W(E,{variant:Q.variant,children:Q.label})},...q.last_engagement_at?[{label:"Last contact",value:Z("span",{children:[W("span",{className:"text-text",children:q.last_engagement_kind||"engagement"}),Z("span",{className:"text-text-dim",children:[" · ",U(q.last_engagement_at)]})]})}]:[]]})]})]})}export{k as default};
|
|
2
|
+
|
|
3
|
+
//# debugId=91847A823E94E6A764756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ui/hubspot/ContactCard.tsx", "../../../src/ui/hubspot/lib/hubspot.tsx"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"// ContactCard — single HubSpot contact. Avatar (Gravatar from email\n// or monogram fallback) + identity, lifecycle pill, last-engagement\n// hint. The card the email-monitor demo wants when the agent is\n// reasoning about a person rather than a deal.\n\nimport { Card, CardHeader, StatusPill, Avatar, DataList } from \"@apteva/ui-kit\";\nimport { lifecycleMeta, recordUrl, pillToDot, timeAgo, minusHoursISO, hubspotVendor } from \"./lib/hubspot\";\n\ninterface Props {\n contact_id: string;\n firstname?: string;\n lastname?: string;\n email?: string;\n phone?: string;\n jobtitle?: string;\n lifecyclestage?: string;\n /** Pre-resolved by the agent (HubSpot returns associated company id). */\n company_name?: string;\n company_domain?: string;\n /** ISO timestamp of the most recent engagement (email open, call,\n * note, etc.) — surfaced as\"emailed 3d ago\" /\"no contact in 14d\". */\n last_engagement_at?: string;\n last_engagement_kind?: string;\n portal_id?: string;\n preview?: boolean;\n projectId?: string;\n}\n\nconst previewSample: Required<Pick<Props,\n |\"contact_id\" |\"firstname\" |\"lastname\" |\"email\" |\"phone\"\n |\"jobtitle\" |\"lifecyclestage\" |\"company_name\"\n |\"company_domain\" |\"last_engagement_at\" |\"last_engagement_kind\"\n |\"portal_id\"\n>> = {\n contact_id: \"501\",\n firstname: \"Sarah\",\n lastname: \"Chen\",\n email: \"sarah.chen@acme-logistics.com\",\n phone: \"+1 312 555 0142\",\n jobtitle: \"VP Operations\",\n lifecyclestage: \"customer\",\n company_name: \"Acme Logistics\",\n company_domain: \"acme-logistics.com\",\n last_engagement_at: minusHoursISO(72),\n last_engagement_kind: \"email\",\n portal_id: \"0\",\n};\n\nfunction gravatarFor(email: string | undefined): string | undefined {\n if (!email) return undefined;\n // Use Gravatar identicon fallback — no MD5 needed if we accept the\n // Google s2 favicon trick won't work for emails. Skip rather than\n // ship a hash impl in v1; Avatar component will monogram.\n return undefined;\n}\n\nexport default function ContactCard(props: Props) {\n const p: Props = props.preview ? { ...previewSample, ...props } : props;\n const lifecycle = lifecycleMeta(p.lifecyclestage);\n const url = recordUrl(\"contact\", p.contact_id, p.portal_id);\n const fullName = [p.firstname, p.lastname].filter(Boolean).join(\" \") || p.email || `Contact ${p.contact_id}`;\n\n return (\n <Card>\n <CardHeader\n vendor={hubspotVendor}\n title={fullName}\n subtitle={p.jobtitle || p.email}\n status={{ label: lifecycle.label, variant: pillToDot(lifecycle.variant) }}\n action={{ label: \"View in HubSpot\", href: url }}\n />\n <div className=\"px-3 py-3 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n <Avatar src={gravatarFor(p.email)} name={fullName} size={32} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-text font-medium truncate\">{fullName}</div>\n {p.jobtitle && p.company_name && (\n <div className=\"text-text-dim text-xs truncate\">\n {p.jobtitle} · {p.company_name}\n </div>\n )}\n </div>\n </div>\n\n <DataList\n items={[\n ...(p.email ? [{ label: \"Email\", value: <a href={`mailto:${p.email}`} className=\"text-accent hover:underline\">{p.email}</a> }] : []),\n ...(p.phone ? [{ label: \"Phone\", value: <span className=\"tabular-nums\">{p.phone}</span> }] : []),\n { label: \"Lifecycle\", value: <StatusPill variant={lifecycle.variant}>{lifecycle.label}</StatusPill> },\n ...(p.last_engagement_at ? [{\n label: \"Last contact\",\n value: (\n <span>\n <span className=\"text-text\">{p.last_engagement_kind || \"engagement\"}</span>\n <span className=\"text-text-dim\"> · {timeAgo(p.last_engagement_at)}</span>\n </span>\n ),\n }] : []),\n ]}\n />\n </div>\n </Card>\n );\n}\n",
|
|
6
|
+
"// Shared helpers for every HubSpot UI component.\n//\n// * pill metadata for deal stages, ticket priorities, lifecycle\n// stages — one source of truth for label + color across cards\n// * formatters: USD, relative date, relative time-since\n// * URL builders for HubSpot canonical record links\n// * favicon helper (Google s2)\n// * pillToDot — bridges StatusPill variant → StatusDot variant for\n// CardHeader's status slot\n// * HubSpot brand mark SVG used in every card header\n\nimport type { StatusDotVariant, StatusPillVariant } from \"@apteva/ui-kit\";\n\n// ─── pill metadata ────────────────────────────────────────────────\n\nexport type PillMeta = { label: string; variant: StatusPillVariant };\n\nconst DEAL_STAGE: Record<string, PillMeta> = {\n appointmentscheduled: { label: \"Appointment scheduled\", variant: \"info\" },\n qualifiedtobuy: { label: \"Qualified to buy\", variant: \"info\" },\n presentationscheduled: { label: \"Presentation scheduled\", variant: \"info\" },\n decisionmakerboughtin: { label: \"Decision-maker bought in \", variant: \"info\" },\n contractsent: { label: \"Contract sent\", variant: \"warn\" },\n closedwon: { label: \"Closed (won)\", variant: \"success\" },\n closedlost: { label: \"Closed (lost)\", variant: \"error\" },\n};\n\nexport function dealStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = DEAL_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst TICKET_PRIORITY: Record<string, PillMeta> = {\n LOW: { label: \"Low\", variant: \"neutral\" },\n MEDIUM: { label: \"Medium\", variant: \"info\" },\n HIGH: { label: \"High\", variant: \"warn\" },\n URGENT: { label: \"Urgent\", variant: \"error\" },\n};\n\nexport function ticketPriorityMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return TICKET_PRIORITY[id] ?? { label: id, variant: \"neutral\" };\n}\n\nconst TICKET_STAGE: Record<string, PillMeta> = {\n \"1\": { label: \"New\", variant: \"info\" },\n \"2\": { label: \"Waiting on us\", variant: \"warn\" },\n \"3\": { label: \"Waiting on them\", variant: \"neutral\" },\n \"4\": { label: \"Closed\", variant: \"success\" },\n};\n\nexport function ticketStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = TICKET_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst LIFECYCLE: Record<string, PillMeta> = {\n subscriber: { label: \"Subscriber\", variant: \"neutral\" },\n lead: { label: \"Lead\", variant: \"neutral\" },\n marketingqualifiedlead: { label: \"MQL\", variant: \"info\" },\n salesqualifiedlead: { label: \"SQL\", variant: \"info\" },\n opportunity: { label: \"Opportunity\", variant: \"info\" },\n customer: { label: \"Customer\", variant: \"success\" },\n evangelist: { label: \"Evangelist\", variant: \"success\" },\n other: { label: \"Other\", variant: \"neutral\" },\n};\n\nexport function lifecycleMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return LIFECYCLE[id] ?? { label: id, variant: \"neutral\" };\n}\n\n// ─── formatters ───────────────────────────────────────────────────\n\nexport function formatUSD(raw: string | number | undefined | null): string {\n if (raw === undefined || raw === null || raw === \"\") return \"—\";\n const n = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(n)) return String(raw);\n return n.toLocaleString(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: n >= 1000 ? 0 : 2,\n });\n}\n\nexport function formatRelativeDate(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const now = new Date();\n const days = Math.round((d.getTime() - now.getTime()) / 86_400_000);\n const dateStr = d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n if (days === 0) return `${dateStr} · today`;\n if (days > 0) return `${dateStr} · in ${days} day${days === 1 ? \"\" : \"s\"}`;\n const overdue = -days;\n return `${dateStr} · ${overdue} day${overdue === 1 ? \"\" : \"s\"} overdue`;\n}\n\nexport function timeAgo(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const sec = Math.round((Date.now() - d.getTime()) / 1000);\n if (sec < 60) return \"just now\";\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.round(hr / 24);\n if (day < 7) return `${day}d ago`;\n const wk = Math.round(day / 7);\n if (wk < 5) return `${wk}w ago`;\n return d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n}\n\nexport function addDaysISO(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() + n);\n return d.toISOString().slice(0, 10);\n}\n\nexport function minusHoursISO(n: number): string {\n const d = new Date();\n d.setHours(d.getHours() - n);\n return d.toISOString();\n}\n\n// ─── URL builders ─────────────────────────────────────────────────\n\nconst PORTAL_FALLBACK = \"0\";\n\nexport function recordUrl(\n type: \"deal\" | \"company\" | \"contact\" | \"ticket\" | \"engagement\",\n id: string,\n portalId?: string,\n): string {\n const portal = portalId || PORTAL_FALLBACK;\n return `https://app.hubspot.com/contacts/${portal}/${type}/${id}`;\n}\n\nexport function pipelineUrl(portalId?: string, pipeline?: string): string {\n const portal = portalId || PORTAL_FALLBACK;\n const path = pipeline ? `?pipeline=${encodeURIComponent(pipeline)}` : \"\";\n return `https://app.hubspot.com/pipelines/${portal}/deals${path}`;\n}\n\n// ─── favicon helper ───────────────────────────────────────────────\n\nexport function faviconFor(domain: string | undefined, size = 32): string | undefined {\n if (!domain) return undefined;\n return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`;\n}\n\n// ─── pill → dot bridge ────────────────────────────────────────────\n//\n// CardHeader's status slot wants a StatusDot variant. StatusPill's\n// variant set is wider; this is the canonical mapping.\n\nexport function pillToDot(v: StatusPillVariant): StatusDotVariant {\n switch (v) {\n case \"success\": return \"live\";\n case \"info\": return \"active\";\n case \"warn\": return \"warn\";\n case \"error\": return \"error\";\n default: return \"muted\";\n }\n}\n\n// ─── HubSpot brand mark ───────────────────────────────────────────\n//\n// Simplified mark — three satellites linked to a central node. Reads\n// at 14×14 without shipping the full brand artwork. Uses currentColor\n// so the consumer can recolor it (CardHeader's vendor strip pipes the\n// HubSpot brand orange in via inline `style.color`).\n\nimport type { ReactNode } from \"react\";\nimport type { CardVendor } from \"@apteva/ui-kit\";\n\nexport const hubspotLogo: ReactNode = (\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden>\n <circle cx=\"18\" cy=\"6\" r=\"2.2\" />\n <circle cx=\"18\" cy=\"18\" r=\"2.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"2.2\" />\n <circle cx=\"14\" cy=\"12\" r=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" fill=\"none\" />\n </svg>\n);\n\n// HubSpot's official brand orange. Passed through CardHeader's\n// `vendor.color` so the brand strip on every HubSpot-emitted card\n// reads as obviously HubSpot at a glance, in both light and dark.\nexport const HUBSPOT_BRAND_COLOR = \"#FF7A59\";\n\nexport const hubspotVendor: CardVendor = {\n name: \"HubSpot\",\n logo: hubspotLogo,\n color: HUBSPOT_BRAND_COLOR,\n};\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "91847A823E94E6A764756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface ContactRow {
|
|
2
|
+
contact_id: string;
|
|
3
|
+
firstname?: string;
|
|
4
|
+
lastname?: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
jobtitle?: string;
|
|
7
|
+
company_name?: string;
|
|
8
|
+
last_engagement_at?: string;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
items?: ContactRow[];
|
|
12
|
+
title?: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
max_rows?: number;
|
|
15
|
+
portal_id?: string;
|
|
16
|
+
preview?: boolean;
|
|
17
|
+
projectId?: string;
|
|
18
|
+
}
|
|
19
|
+
export default function ContactList(props: Props): import("react").JSX.Element;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=ContactList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContactList.d.ts","sourceRoot":"","sources":["../../../src/ui/hubspot/ContactList.tsx"],"names":[],"mappings":"AAMA,UAAU,UAAU;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,UAAU,KAAK;IACd,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAaD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAK,EAAE,KAAK,+BAuC/C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// ContactList — dense rows of contacts. Avatar leading, name + title,
|
|
2
|
+
// company chip + last engagement on the right.
|
|
3
|
+
import { Card, CardHeader, Avatar, Row } from "@apteva/ui-kit";
|
|
4
|
+
import { recordUrl, timeAgo, minusHoursISO, hubspotVendor } from "./lib/hubspot";
|
|
5
|
+
const previewItems = [
|
|
6
|
+
{ contact_id: "1", firstname: "Sarah", lastname: "Chen", email: "sarah.chen@acme-logistics.com", jobtitle: "VP Operations", company_name: "Acme Logistics", last_engagement_at: minusHoursISO(2) },
|
|
7
|
+
{ contact_id: "2", firstname: "David", lastname: "Park", email: "david.park@globex-innovations.com", jobtitle: "CTO", company_name: "Globex Innovations", last_engagement_at: minusHoursISO(336) },
|
|
8
|
+
{ contact_id: "3", firstname: "Lisa", lastname: "Rodriguez", email: "lisa.rodriguez@initech-corp.com", jobtitle: "CFO", company_name: "Initech Corp", last_engagement_at: minusHoursISO(36) },
|
|
9
|
+
{ contact_id: "4", firstname: "Marcus", lastname: "Hayes", email: "marcus.hayes@acme-logistics.com", jobtitle: "IT Director", company_name: "Acme Logistics", last_engagement_at: minusHoursISO(168) },
|
|
10
|
+
];
|
|
11
|
+
function nameOf(c) {
|
|
12
|
+
return [c.firstname, c.lastname].filter(Boolean).join(" ") || c.email || `Contact ${c.contact_id}`;
|
|
13
|
+
}
|
|
14
|
+
export default function ContactList(props) {
|
|
15
|
+
const items = props.preview ? (props.items ?? previewItems) : (props.items ?? []);
|
|
16
|
+
const max = props.max_rows ?? 6;
|
|
17
|
+
const visible = items.slice(0, max);
|
|
18
|
+
const overflow = items.length - visible.length;
|
|
19
|
+
return (<Card fullWidth>
|
|
20
|
+
<CardHeader vendor={hubspotVendor} title={props.title || "Contacts"} subtitle={props.subtitle || (items.length > 0 ? `${items.length} contact${items.length === 1 ? "" : "s"}` : "No contacts")}/>
|
|
21
|
+
{visible.length === 0 && (<div className="px-3 py-3 text-xs text-text-dim">No contacts match.</div>)}
|
|
22
|
+
{visible.map((c, i) => {
|
|
23
|
+
const name = nameOf(c);
|
|
24
|
+
return (<Row key={c.contact_id} flush={i === 0} href={recordUrl("contact", c.contact_id, props.portal_id)} leading={<Avatar src="" name={name} size={20}/>} title={name} subtitle={[c.jobtitle, c.company_name].filter(Boolean).join(" ·")} trailing={c.last_engagement_at && (<span className="text-text-dim tabular-nums">{timeAgo(c.last_engagement_at)}</span>)}/>);
|
|
25
|
+
})}
|
|
26
|
+
{overflow > 0 && (<div className="px-3 py-1.5 text-[11px] text-text-dim border-t border-border">
|
|
27
|
+
+{overflow} more
|
|
28
|
+
</div>)}
|
|
29
|
+
</Card>);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ContactList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContactList.js","sourceRoot":"","sources":["../../../src/ui/hubspot/ContactList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Card as x,CardHeader as $,Avatar as p,Row as V}from"@apteva/ui-kit";import{jsx as l,jsxs as N}from"react/jsx-runtime";function _(t){if(!t)return"—";let e=new Date(t);if(Number.isNaN(e.getTime()))return t;let m=Math.round((Date.now()-e.getTime())/1000);if(m<60)return"just now";let n=Math.round(m/60);if(n<60)return`${n}m ago`;let c=Math.round(n/60);if(c<24)return`${c}h ago`;let a=Math.round(c/24);if(a<7)return`${a}d ago`;let g=Math.round(a/7);if(g<5)return`${g}w ago`;return e.toLocaleDateString("en-US",{month:"short",day:"numeric"})}function o(t){let e=new Date;return e.setHours(e.getHours()-t),e.toISOString()}var u="0";function f(t,e,m){return`https://app.hubspot.com/contacts/${m||u}/${t}/${e}`}var h=N("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:[l("circle",{cx:"18",cy:"6",r:"2.2"}),l("circle",{cx:"18",cy:"18",r:"2.2"}),l("circle",{cx:"6",cy:"12",r:"2.2"}),l("circle",{cx:"14",cy:"12",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.5"}),l("path",{d:"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8",stroke:"currentColor",strokeWidth:"1.2",fill:"none"})]}),C="#FF7A59",r={name:"HubSpot",logo:h,color:C};import{jsx as s,jsxs as b}from"react/jsx-runtime";var y=[{contact_id:"1",firstname:"Sarah",lastname:"Chen",email:"sarah.chen@acme-logistics.com",jobtitle:"VP Operations",company_name:"Acme Logistics",last_engagement_at:o(2)},{contact_id:"2",firstname:"David",lastname:"Park",email:"david.park@globex-innovations.com",jobtitle:"CTO",company_name:"Globex Innovations",last_engagement_at:o(336)},{contact_id:"3",firstname:"Lisa",lastname:"Rodriguez",email:"lisa.rodriguez@initech-corp.com",jobtitle:"CFO",company_name:"Initech Corp",last_engagement_at:o(36)},{contact_id:"4",firstname:"Marcus",lastname:"Hayes",email:"marcus.hayes@acme-logistics.com",jobtitle:"IT Director",company_name:"Acme Logistics",last_engagement_at:o(168)}];function z(t){return[t.firstname,t.lastname].filter(Boolean).join(" ")||t.email||`Contact ${t.contact_id}`}function H(t){let e=t.preview?t.items??y:t.items??[],m=t.max_rows??6,n=e.slice(0,m),c=e.length-n.length;return b(x,{fullWidth:!0,children:[s($,{vendor:r,title:t.title||"Contacts",subtitle:t.subtitle||(e.length>0?`${e.length} contact${e.length===1?"":"s"}`:"No contacts")}),n.length===0&&s("div",{className:"px-3 py-3 text-xs text-text-dim",children:"No contacts match."}),n.map((a,g)=>{let i=z(a);return s(V,{flush:g===0,href:f("contact",a.contact_id,t.portal_id),leading:s(p,{src:"",name:i,size:20}),title:i,subtitle:[a.jobtitle,a.company_name].filter(Boolean).join(" ·"),trailing:a.last_engagement_at&&s("span",{className:"text-text-dim tabular-nums",children:_(a.last_engagement_at)})},a.contact_id)}),c>0&&b("div",{className:"px-3 py-1.5 text-[11px] text-text-dim border-t border-border",children:["+",c," more"]})]})}export{H as default};
|
|
2
|
+
|
|
3
|
+
//# debugId=35CA26A1BCEE2F4B64756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ui/hubspot/ContactList.tsx", "../../../src/ui/hubspot/lib/hubspot.tsx"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"// ContactList — dense rows of contacts. Avatar leading, name + title,\n// company chip + last engagement on the right.\n\nimport { Card, CardHeader, Avatar, Row } from \"@apteva/ui-kit\";\nimport { recordUrl, timeAgo, minusHoursISO, hubspotVendor } from \"./lib/hubspot\";\n\ninterface ContactRow {\n contact_id: string;\n firstname?: string;\n lastname?: string;\n email?: string;\n jobtitle?: string;\n company_name?: string;\n last_engagement_at?: string;\n}\n\ninterface Props {\n items?: ContactRow[];\n title?: string;\n subtitle?: string;\n max_rows?: number;\n portal_id?: string;\n preview?: boolean;\n projectId?: string;\n}\n\nconst previewItems: ContactRow[] = [\n { contact_id: \"1\", firstname: \"Sarah\", lastname: \"Chen\", email: \"sarah.chen@acme-logistics.com\", jobtitle: \"VP Operations\", company_name: \"Acme Logistics\", last_engagement_at: minusHoursISO(2) },\n { contact_id: \"2\", firstname: \"David\", lastname: \"Park\", email: \"david.park@globex-innovations.com\", jobtitle: \"CTO\", company_name: \"Globex Innovations\", last_engagement_at: minusHoursISO(336) },\n { contact_id: \"3\", firstname: \"Lisa\", lastname: \"Rodriguez\", email: \"lisa.rodriguez@initech-corp.com\", jobtitle: \"CFO\", company_name: \"Initech Corp\", last_engagement_at: minusHoursISO(36) },\n { contact_id: \"4\", firstname: \"Marcus\", lastname: \"Hayes\", email: \"marcus.hayes@acme-logistics.com\", jobtitle: \"IT Director\", company_name: \"Acme Logistics\", last_engagement_at: minusHoursISO(168) },\n];\n\nfunction nameOf(c: ContactRow): string {\n return [c.firstname, c.lastname].filter(Boolean).join(\" \") || c.email || `Contact ${c.contact_id}`;\n}\n\nexport default function ContactList(props: Props) {\n const items = props.preview ? (props.items ?? previewItems) : (props.items ?? []);\n const max = props.max_rows ?? 6;\n const visible = items.slice(0, max);\n const overflow = items.length - visible.length;\n\n return (\n <Card fullWidth>\n <CardHeader\n vendor={hubspotVendor}\n title={props.title || \"Contacts\"}\n subtitle={props.subtitle || (items.length > 0 ? `${items.length} contact${items.length === 1 ? \"\" :\"s\"}` :\"No contacts\")}\n />\n {visible.length === 0 && (\n <div className=\"px-3 py-3 text-xs text-text-dim\">No contacts match.</div>\n )}\n {visible.map((c, i) => {\n const name = nameOf(c);\n return (\n <Row\n key={c.contact_id}\n flush={i === 0}\n href={recordUrl(\"contact\", c.contact_id, props.portal_id)}\n leading={<Avatar src=\"\" name={name} size={20} />}\n title={name}\n subtitle={[c.jobtitle, c.company_name].filter(Boolean).join(\" ·\")}\n trailing={c.last_engagement_at && (\n <span className=\"text-text-dim tabular-nums\">{timeAgo(c.last_engagement_at)}</span>\n )}\n />\n );\n })}\n {overflow > 0 && (\n <div className=\"px-3 py-1.5 text-[11px] text-text-dim border-t border-border\">\n +{overflow} more\n </div>\n )}\n </Card>\n );\n}\n",
|
|
6
|
+
"// Shared helpers for every HubSpot UI component.\n//\n// * pill metadata for deal stages, ticket priorities, lifecycle\n// stages — one source of truth for label + color across cards\n// * formatters: USD, relative date, relative time-since\n// * URL builders for HubSpot canonical record links\n// * favicon helper (Google s2)\n// * pillToDot — bridges StatusPill variant → StatusDot variant for\n// CardHeader's status slot\n// * HubSpot brand mark SVG used in every card header\n\nimport type { StatusDotVariant, StatusPillVariant } from \"@apteva/ui-kit\";\n\n// ─── pill metadata ────────────────────────────────────────────────\n\nexport type PillMeta = { label: string; variant: StatusPillVariant };\n\nconst DEAL_STAGE: Record<string, PillMeta> = {\n appointmentscheduled: { label: \"Appointment scheduled\", variant: \"info\" },\n qualifiedtobuy: { label: \"Qualified to buy\", variant: \"info\" },\n presentationscheduled: { label: \"Presentation scheduled\", variant: \"info\" },\n decisionmakerboughtin: { label: \"Decision-maker bought in \", variant: \"info\" },\n contractsent: { label: \"Contract sent\", variant: \"warn\" },\n closedwon: { label: \"Closed (won)\", variant: \"success\" },\n closedlost: { label: \"Closed (lost)\", variant: \"error\" },\n};\n\nexport function dealStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = DEAL_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst TICKET_PRIORITY: Record<string, PillMeta> = {\n LOW: { label: \"Low\", variant: \"neutral\" },\n MEDIUM: { label: \"Medium\", variant: \"info\" },\n HIGH: { label: \"High\", variant: \"warn\" },\n URGENT: { label: \"Urgent\", variant: \"error\" },\n};\n\nexport function ticketPriorityMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return TICKET_PRIORITY[id] ?? { label: id, variant: \"neutral\" };\n}\n\nconst TICKET_STAGE: Record<string, PillMeta> = {\n \"1\": { label: \"New\", variant: \"info\" },\n \"2\": { label: \"Waiting on us\", variant: \"warn\" },\n \"3\": { label: \"Waiting on them\", variant: \"neutral\" },\n \"4\": { label: \"Closed\", variant: \"success\" },\n};\n\nexport function ticketStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = TICKET_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst LIFECYCLE: Record<string, PillMeta> = {\n subscriber: { label: \"Subscriber\", variant: \"neutral\" },\n lead: { label: \"Lead\", variant: \"neutral\" },\n marketingqualifiedlead: { label: \"MQL\", variant: \"info\" },\n salesqualifiedlead: { label: \"SQL\", variant: \"info\" },\n opportunity: { label: \"Opportunity\", variant: \"info\" },\n customer: { label: \"Customer\", variant: \"success\" },\n evangelist: { label: \"Evangelist\", variant: \"success\" },\n other: { label: \"Other\", variant: \"neutral\" },\n};\n\nexport function lifecycleMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return LIFECYCLE[id] ?? { label: id, variant: \"neutral\" };\n}\n\n// ─── formatters ───────────────────────────────────────────────────\n\nexport function formatUSD(raw: string | number | undefined | null): string {\n if (raw === undefined || raw === null || raw === \"\") return \"—\";\n const n = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(n)) return String(raw);\n return n.toLocaleString(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: n >= 1000 ? 0 : 2,\n });\n}\n\nexport function formatRelativeDate(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const now = new Date();\n const days = Math.round((d.getTime() - now.getTime()) / 86_400_000);\n const dateStr = d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n if (days === 0) return `${dateStr} · today`;\n if (days > 0) return `${dateStr} · in ${days} day${days === 1 ? \"\" : \"s\"}`;\n const overdue = -days;\n return `${dateStr} · ${overdue} day${overdue === 1 ? \"\" : \"s\"} overdue`;\n}\n\nexport function timeAgo(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const sec = Math.round((Date.now() - d.getTime()) / 1000);\n if (sec < 60) return \"just now\";\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.round(hr / 24);\n if (day < 7) return `${day}d ago`;\n const wk = Math.round(day / 7);\n if (wk < 5) return `${wk}w ago`;\n return d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n}\n\nexport function addDaysISO(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() + n);\n return d.toISOString().slice(0, 10);\n}\n\nexport function minusHoursISO(n: number): string {\n const d = new Date();\n d.setHours(d.getHours() - n);\n return d.toISOString();\n}\n\n// ─── URL builders ─────────────────────────────────────────────────\n\nconst PORTAL_FALLBACK = \"0\";\n\nexport function recordUrl(\n type: \"deal\" | \"company\" | \"contact\" | \"ticket\" | \"engagement\",\n id: string,\n portalId?: string,\n): string {\n const portal = portalId || PORTAL_FALLBACK;\n return `https://app.hubspot.com/contacts/${portal}/${type}/${id}`;\n}\n\nexport function pipelineUrl(portalId?: string, pipeline?: string): string {\n const portal = portalId || PORTAL_FALLBACK;\n const path = pipeline ? `?pipeline=${encodeURIComponent(pipeline)}` : \"\";\n return `https://app.hubspot.com/pipelines/${portal}/deals${path}`;\n}\n\n// ─── favicon helper ───────────────────────────────────────────────\n\nexport function faviconFor(domain: string | undefined, size = 32): string | undefined {\n if (!domain) return undefined;\n return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`;\n}\n\n// ─── pill → dot bridge ────────────────────────────────────────────\n//\n// CardHeader's status slot wants a StatusDot variant. StatusPill's\n// variant set is wider; this is the canonical mapping.\n\nexport function pillToDot(v: StatusPillVariant): StatusDotVariant {\n switch (v) {\n case \"success\": return \"live\";\n case \"info\": return \"active\";\n case \"warn\": return \"warn\";\n case \"error\": return \"error\";\n default: return \"muted\";\n }\n}\n\n// ─── HubSpot brand mark ───────────────────────────────────────────\n//\n// Simplified mark — three satellites linked to a central node. Reads\n// at 14×14 without shipping the full brand artwork. Uses currentColor\n// so the consumer can recolor it (CardHeader's vendor strip pipes the\n// HubSpot brand orange in via inline `style.color`).\n\nimport type { ReactNode } from \"react\";\nimport type { CardVendor } from \"@apteva/ui-kit\";\n\nexport const hubspotLogo: ReactNode = (\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden>\n <circle cx=\"18\" cy=\"6\" r=\"2.2\" />\n <circle cx=\"18\" cy=\"18\" r=\"2.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"2.2\" />\n <circle cx=\"14\" cy=\"12\" r=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" fill=\"none\" />\n </svg>\n);\n\n// HubSpot's official brand orange. Passed through CardHeader's\n// `vendor.color` so the brand strip on every HubSpot-emitted card\n// reads as obviously HubSpot at a glance, in both light and dark.\nexport const HUBSPOT_BRAND_COLOR = \"#FF7A59\";\n\nexport const hubspotVendor: CardVendor = {\n name: \"HubSpot\",\n logo: hubspotLogo,\n color: HUBSPOT_BRAND_COLOR,\n};\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "35CA26A1BCEE2F4B64756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
deal_id: string;
|
|
3
|
+
dealname?: string;
|
|
4
|
+
amount?: string;
|
|
5
|
+
/** Internal stage id (e.g."contractsent"). */
|
|
6
|
+
dealstage?: string;
|
|
7
|
+
/** Optional human label override for custom pipelines. */
|
|
8
|
+
dealstage_label?: string;
|
|
9
|
+
pipeline?: string;
|
|
10
|
+
/** ISO date for the expected close date. */
|
|
11
|
+
closedate?: string;
|
|
12
|
+
owner_email?: string;
|
|
13
|
+
company_name?: string;
|
|
14
|
+
company_domain?: string;
|
|
15
|
+
/** HubSpot portal id — required to build the canonical record URL.
|
|
16
|
+
* Absent → the link still resolves via HubSpot's portal redirect. */
|
|
17
|
+
portal_id?: string;
|
|
18
|
+
preview?: boolean;
|
|
19
|
+
projectId?: string;
|
|
20
|
+
}
|
|
21
|
+
export default function DealCard(props: Props): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=DealCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DealCard.d.ts","sourceRoot":"","sources":["../../../src/ui/hubspot/DealCard.tsx"],"names":[],"mappings":"AAgBA,UAAU,KAAK;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;wEACoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAmBD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,KAAK,+BAuD5C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// DealCard — chat-attachment / dashboard-tile card for a single
|
|
2
|
+
// HubSpot deal.
|
|
3
|
+
//
|
|
4
|
+
// The agent calls
|
|
5
|
+
// respond(components=[{ app: "hubspot", name: "deal-card", props:{...}}])
|
|
6
|
+
// after a search_crm_objects (objectType=deals) or get-by-id, and
|
|
7
|
+
// passes the deal's HubSpot properties through almost verbatim. Field
|
|
8
|
+
// names mirror the HubSpot wire format (dealname, amount, dealstage,
|
|
9
|
+
// closedate, …) so the agent rarely needs to rename anything.
|
|
10
|
+
import { Card, CardHeader, StatusPill, Avatar, DataList } from "@apteva/ui-kit";
|
|
11
|
+
import { dealStageMeta, formatUSD, formatRelativeDate, recordUrl, faviconFor, pillToDot, addDaysISO, hubspotVendor, } from "./lib/hubspot";
|
|
12
|
+
const previewSample = {
|
|
13
|
+
deal_id: "9876543210",
|
|
14
|
+
dealname: "Acme Q4 Renewal",
|
|
15
|
+
amount: "48000",
|
|
16
|
+
dealstage: "contractsent",
|
|
17
|
+
pipeline: "default",
|
|
18
|
+
closedate: addDaysISO(7),
|
|
19
|
+
owner_email: "marc-olivier@apteva.local",
|
|
20
|
+
company_name: "Acme Logistics",
|
|
21
|
+
company_domain: "acme-logistics.com",
|
|
22
|
+
portal_id: "0",
|
|
23
|
+
};
|
|
24
|
+
export default function DealCard(props) {
|
|
25
|
+
const p = props.preview ? { ...previewSample, ...props } : props;
|
|
26
|
+
const stage = dealStageMeta(p.dealstage, p.dealstage_label);
|
|
27
|
+
const url = recordUrl("deal", p.deal_id, p.portal_id);
|
|
28
|
+
return (<Card>
|
|
29
|
+
<CardHeader vendor={hubspotVendor} title={p.company_name || "HubSpot deal"} subtitle={p.dealname || `Deal ${p.deal_id}`} status={{ label: stage.label, variant: pillToDot(stage.variant) }} action={{ label: "View in HubSpot", href: url }}/>
|
|
30
|
+
<div className="px-3 py-3 flex flex-col gap-3">
|
|
31
|
+
<div className="flex items-baseline justify-between gap-2">
|
|
32
|
+
<span className="text-text text-lg font-semibold tabular-nums">
|
|
33
|
+
{formatUSD(p.amount)}
|
|
34
|
+
</span>
|
|
35
|
+
<StatusPill variant={stage.variant}>{stage.label}</StatusPill>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<DataList items={[
|
|
39
|
+
{
|
|
40
|
+
label: "Close date",
|
|
41
|
+
value: <span className="tabular-nums">{formatRelativeDate(p.closedate)}</span>,
|
|
42
|
+
},
|
|
43
|
+
...(p.pipeline ? [{ label: "Pipeline", value: p.pipeline }] : []),
|
|
44
|
+
...(p.company_name ? [{
|
|
45
|
+
label: "Company",
|
|
46
|
+
value: (<span className="inline-flex items-center gap-1.5">
|
|
47
|
+
{p.company_domain && (<img src={faviconFor(p.company_domain)} alt="" width={12} height={12} className="rounded-sm"/>)}
|
|
48
|
+
<span className="text-text">{p.company_name}</span>
|
|
49
|
+
{p.company_domain && <span className="text-text-dim">· {p.company_domain}</span>}
|
|
50
|
+
</span>),
|
|
51
|
+
}] : []),
|
|
52
|
+
...(p.owner_email ? [{
|
|
53
|
+
label: "Owner",
|
|
54
|
+
value: (<span className="inline-flex items-center gap-1.5">
|
|
55
|
+
<Avatar src="" name={p.owner_email} size={14}/>
|
|
56
|
+
<span className="text-text">{p.owner_email}</span>
|
|
57
|
+
</span>),
|
|
58
|
+
}] : []),
|
|
59
|
+
]}/>
|
|
60
|
+
</div>
|
|
61
|
+
</Card>);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=DealCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DealCard.js","sourceRoot":"","sources":["../../../src/ui/hubspot/DealCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Card as O,CardHeader as _,StatusPill as g,Avatar as R,DataList as C}from"@apteva/ui-kit";import{jsx as q,jsxs as E}from"react/jsx-runtime";var U={appointmentscheduled:{label:"Appointment scheduled",variant:"info"},qualifiedtobuy:{label:"Qualified to buy",variant:"info"},presentationscheduled:{label:"Presentation scheduled",variant:"info"},decisionmakerboughtin:{label:"Decision-maker bought in ",variant:"info"},contractsent:{label:"Contract sent",variant:"warn"},closedwon:{label:"Closed (won)",variant:"success"},closedlost:{label:"Closed (lost)",variant:"error"}};function V(Q,J){if(!Q)return{label:J??"—",variant:"neutral"};let W=U[Q];if(W)return{label:J??W.label,variant:W.variant};return{label:J??Q,variant:"neutral"}}function z(Q){if(Q===void 0||Q===null||Q==="")return"—";let J=typeof Q==="number"?Q:Number(Q);if(!Number.isFinite(J))return String(Q);return J.toLocaleString("en-US",{style:"currency",currency:"USD",maximumFractionDigits:J>=1000?0:2})}function G(Q){if(!Q)return"—";let J=new Date(Q);if(Number.isNaN(J.getTime()))return Q;let W=new Date,Z=Math.round((J.getTime()-W.getTime())/86400000),M=J.toLocaleDateString("en-US",{month:"short",day:"numeric"});if(Z===0)return`${M} · today`;if(Z>0)return`${M} · in ${Z} day${Z===1?"":"s"}`;let N=-Z;return`${M} · ${N} day${N===1?"":"s"} overdue`}function Y(Q){let J=new Date;return J.setDate(J.getDate()+Q),J.toISOString().slice(0,10)}var H="0";function f(Q,J,W){return`https://app.hubspot.com/contacts/${W||H}/${Q}/${J}`}function B(Q,J=32){if(!Q)return;return`https://www.google.com/s2/favicons?domain=${encodeURIComponent(Q)}&sz=${J}`}function F(Q){switch(Q){case"success":return"live";case"info":return"active";case"warn":return"warn";case"error":return"error";default:return"muted"}}var P=E("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:[q("circle",{cx:"18",cy:"6",r:"2.2"}),q("circle",{cx:"18",cy:"18",r:"2.2"}),q("circle",{cx:"6",cy:"12",r:"2.2"}),q("circle",{cx:"14",cy:"12",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.5"}),q("path",{d:"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8",stroke:"currentColor",strokeWidth:"1.2",fill:"none"})]}),D="#FF7A59",K={name:"HubSpot",logo:P,color:D};import{jsx as X,jsxs as $}from"react/jsx-runtime";var I={deal_id:"9876543210",dealname:"Acme Q4 Renewal",amount:"48000",dealstage:"contractsent",pipeline:"default",closedate:Y(7),owner_email:"marc-olivier@apteva.local",company_name:"Acme Logistics",company_domain:"acme-logistics.com",portal_id:"0"};function b(Q){let J=Q.preview?{...I,...Q}:Q,W=V(J.dealstage,J.dealstage_label),Z=f("deal",J.deal_id,J.portal_id);return $(O,{children:[X(_,{vendor:K,title:J.company_name||"HubSpot deal",subtitle:J.dealname||`Deal ${J.deal_id}`,status:{label:W.label,variant:F(W.variant)},action:{label:"View in HubSpot",href:Z}}),$("div",{className:"px-3 py-3 flex flex-col gap-3",children:[$("div",{className:"flex items-baseline justify-between gap-2",children:[X("span",{className:"text-text text-lg font-semibold tabular-nums",children:z(J.amount)}),X(g,{variant:W.variant,children:W.label})]}),X(C,{items:[{label:"Close date",value:X("span",{className:"tabular-nums",children:G(J.closedate)})},...J.pipeline?[{label:"Pipeline",value:J.pipeline}]:[],...J.company_name?[{label:"Company",value:$("span",{className:"inline-flex items-center gap-1.5",children:[J.company_domain&&X("img",{src:B(J.company_domain),alt:"",width:12,height:12,className:"rounded-sm"}),X("span",{className:"text-text",children:J.company_name}),J.company_domain&&$("span",{className:"text-text-dim",children:["· ",J.company_domain]})]})}]:[],...J.owner_email?[{label:"Owner",value:$("span",{className:"inline-flex items-center gap-1.5",children:[X(R,{src:"",name:J.owner_email,size:14}),X("span",{className:"text-text",children:J.owner_email})]})}]:[]]})]})]})}export{b as default};
|
|
2
|
+
|
|
3
|
+
//# debugId=0AFC5D6EB6E2152964756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ui/hubspot/DealCard.tsx", "../../../src/ui/hubspot/lib/hubspot.tsx"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"// DealCard — chat-attachment / dashboard-tile card for a single\n// HubSpot deal.\n//\n// The agent calls\n// respond(components=[{ app: \"hubspot\", name: \"deal-card\", props:{...}}])\n// after a search_crm_objects (objectType=deals) or get-by-id, and\n// passes the deal's HubSpot properties through almost verbatim. Field\n// names mirror the HubSpot wire format (dealname, amount, dealstage,\n// closedate, …) so the agent rarely needs to rename anything.\n\nimport { Card, CardHeader, StatusPill, Avatar, DataList } from \"@apteva/ui-kit\";\nimport {\n dealStageMeta, formatUSD, formatRelativeDate, recordUrl,\n faviconFor, pillToDot, addDaysISO, hubspotVendor,\n} from \"./lib/hubspot\";\n\ninterface Props {\n deal_id: string;\n dealname?: string;\n amount?: string;\n /** Internal stage id (e.g.\"contractsent\"). */\n dealstage?: string;\n /** Optional human label override for custom pipelines. */\n dealstage_label?: string;\n pipeline?: string;\n /** ISO date for the expected close date. */\n closedate?: string;\n owner_email?: string;\n company_name?: string;\n company_domain?: string;\n /** HubSpot portal id — required to build the canonical record URL.\n * Absent → the link still resolves via HubSpot's portal redirect. */\n portal_id?: string;\n preview?: boolean;\n projectId?: string;\n}\n\nconst previewSample: Required<Pick<Props,\n |\"deal_id\" |\"dealname\" |\"amount\" |\"dealstage\"\n |\"pipeline\" |\"closedate\" |\"owner_email\"\n |\"company_name\" |\"company_domain\" |\"portal_id\"\n>> = {\n deal_id: \"9876543210\",\n dealname: \"Acme Q4 Renewal\",\n amount: \"48000\",\n dealstage: \"contractsent\",\n pipeline: \"default\",\n closedate: addDaysISO(7),\n owner_email: \"marc-olivier@apteva.local\",\n company_name: \"Acme Logistics\",\n company_domain: \"acme-logistics.com\",\n portal_id: \"0\",\n};\n\nexport default function DealCard(props: Props) {\n const p: Props = props.preview ? { ...previewSample, ...props } : props;\n const stage = dealStageMeta(p.dealstage, p.dealstage_label);\n const url = recordUrl(\"deal\", p.deal_id, p.portal_id);\n\n return (\n <Card>\n <CardHeader\n vendor={hubspotVendor}\n title={p.company_name || \"HubSpot deal\"}\n subtitle={p.dealname || `Deal ${p.deal_id}`}\n status={{ label: stage.label, variant: pillToDot(stage.variant) }}\n action={{ label: \"View in HubSpot\", href: url }}\n />\n <div className=\"px-3 py-3 flex flex-col gap-3\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-text text-lg font-semibold tabular-nums\">\n {formatUSD(p.amount)}\n </span>\n <StatusPill variant={stage.variant}>{stage.label}</StatusPill>\n </div>\n\n <DataList\n items={[\n {\n label: \"Close date\",\n value: <span className=\"tabular-nums\">{formatRelativeDate(p.closedate)}</span>,\n },\n ...(p.pipeline ? [{ label: \"Pipeline\", value: p.pipeline }] : []),\n ...(p.company_name ? [{\n label: \"Company\",\n value: (\n <span className=\"inline-flex items-center gap-1.5\">\n {p.company_domain && (\n <img src={faviconFor(p.company_domain)} alt=\"\" width={12} height={12} className=\"rounded-sm\" />\n )}\n <span className=\"text-text\">{p.company_name}</span>\n {p.company_domain && <span className=\"text-text-dim\">· {p.company_domain}</span>}\n </span>\n ),\n }] : []),\n ...(p.owner_email ? [{\n label: \"Owner\",\n value: (\n <span className=\"inline-flex items-center gap-1.5\">\n <Avatar src=\"\" name={p.owner_email} size={14} />\n <span className=\"text-text\">{p.owner_email}</span>\n </span>\n ),\n }] : []),\n ]}\n />\n </div>\n </Card>\n );\n}\n",
|
|
6
|
+
"// Shared helpers for every HubSpot UI component.\n//\n// * pill metadata for deal stages, ticket priorities, lifecycle\n// stages — one source of truth for label + color across cards\n// * formatters: USD, relative date, relative time-since\n// * URL builders for HubSpot canonical record links\n// * favicon helper (Google s2)\n// * pillToDot — bridges StatusPill variant → StatusDot variant for\n// CardHeader's status slot\n// * HubSpot brand mark SVG used in every card header\n\nimport type { StatusDotVariant, StatusPillVariant } from \"@apteva/ui-kit\";\n\n// ─── pill metadata ────────────────────────────────────────────────\n\nexport type PillMeta = { label: string; variant: StatusPillVariant };\n\nconst DEAL_STAGE: Record<string, PillMeta> = {\n appointmentscheduled: { label: \"Appointment scheduled\", variant: \"info\" },\n qualifiedtobuy: { label: \"Qualified to buy\", variant: \"info\" },\n presentationscheduled: { label: \"Presentation scheduled\", variant: \"info\" },\n decisionmakerboughtin: { label: \"Decision-maker bought in \", variant: \"info\" },\n contractsent: { label: \"Contract sent\", variant: \"warn\" },\n closedwon: { label: \"Closed (won)\", variant: \"success\" },\n closedlost: { label: \"Closed (lost)\", variant: \"error\" },\n};\n\nexport function dealStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = DEAL_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst TICKET_PRIORITY: Record<string, PillMeta> = {\n LOW: { label: \"Low\", variant: \"neutral\" },\n MEDIUM: { label: \"Medium\", variant: \"info\" },\n HIGH: { label: \"High\", variant: \"warn\" },\n URGENT: { label: \"Urgent\", variant: \"error\" },\n};\n\nexport function ticketPriorityMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return TICKET_PRIORITY[id] ?? { label: id, variant: \"neutral\" };\n}\n\nconst TICKET_STAGE: Record<string, PillMeta> = {\n \"1\": { label: \"New\", variant: \"info\" },\n \"2\": { label: \"Waiting on us\", variant: \"warn\" },\n \"3\": { label: \"Waiting on them\", variant: \"neutral\" },\n \"4\": { label: \"Closed\", variant: \"success\" },\n};\n\nexport function ticketStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = TICKET_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst LIFECYCLE: Record<string, PillMeta> = {\n subscriber: { label: \"Subscriber\", variant: \"neutral\" },\n lead: { label: \"Lead\", variant: \"neutral\" },\n marketingqualifiedlead: { label: \"MQL\", variant: \"info\" },\n salesqualifiedlead: { label: \"SQL\", variant: \"info\" },\n opportunity: { label: \"Opportunity\", variant: \"info\" },\n customer: { label: \"Customer\", variant: \"success\" },\n evangelist: { label: \"Evangelist\", variant: \"success\" },\n other: { label: \"Other\", variant: \"neutral\" },\n};\n\nexport function lifecycleMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return LIFECYCLE[id] ?? { label: id, variant: \"neutral\" };\n}\n\n// ─── formatters ───────────────────────────────────────────────────\n\nexport function formatUSD(raw: string | number | undefined | null): string {\n if (raw === undefined || raw === null || raw === \"\") return \"—\";\n const n = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(n)) return String(raw);\n return n.toLocaleString(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: n >= 1000 ? 0 : 2,\n });\n}\n\nexport function formatRelativeDate(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const now = new Date();\n const days = Math.round((d.getTime() - now.getTime()) / 86_400_000);\n const dateStr = d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n if (days === 0) return `${dateStr} · today`;\n if (days > 0) return `${dateStr} · in ${days} day${days === 1 ? \"\" : \"s\"}`;\n const overdue = -days;\n return `${dateStr} · ${overdue} day${overdue === 1 ? \"\" : \"s\"} overdue`;\n}\n\nexport function timeAgo(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const sec = Math.round((Date.now() - d.getTime()) / 1000);\n if (sec < 60) return \"just now\";\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.round(hr / 24);\n if (day < 7) return `${day}d ago`;\n const wk = Math.round(day / 7);\n if (wk < 5) return `${wk}w ago`;\n return d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n}\n\nexport function addDaysISO(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() + n);\n return d.toISOString().slice(0, 10);\n}\n\nexport function minusHoursISO(n: number): string {\n const d = new Date();\n d.setHours(d.getHours() - n);\n return d.toISOString();\n}\n\n// ─── URL builders ─────────────────────────────────────────────────\n\nconst PORTAL_FALLBACK = \"0\";\n\nexport function recordUrl(\n type: \"deal\" | \"company\" | \"contact\" | \"ticket\" | \"engagement\",\n id: string,\n portalId?: string,\n): string {\n const portal = portalId || PORTAL_FALLBACK;\n return `https://app.hubspot.com/contacts/${portal}/${type}/${id}`;\n}\n\nexport function pipelineUrl(portalId?: string, pipeline?: string): string {\n const portal = portalId || PORTAL_FALLBACK;\n const path = pipeline ? `?pipeline=${encodeURIComponent(pipeline)}` : \"\";\n return `https://app.hubspot.com/pipelines/${portal}/deals${path}`;\n}\n\n// ─── favicon helper ───────────────────────────────────────────────\n\nexport function faviconFor(domain: string | undefined, size = 32): string | undefined {\n if (!domain) return undefined;\n return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`;\n}\n\n// ─── pill → dot bridge ────────────────────────────────────────────\n//\n// CardHeader's status slot wants a StatusDot variant. StatusPill's\n// variant set is wider; this is the canonical mapping.\n\nexport function pillToDot(v: StatusPillVariant): StatusDotVariant {\n switch (v) {\n case \"success\": return \"live\";\n case \"info\": return \"active\";\n case \"warn\": return \"warn\";\n case \"error\": return \"error\";\n default: return \"muted\";\n }\n}\n\n// ─── HubSpot brand mark ───────────────────────────────────────────\n//\n// Simplified mark — three satellites linked to a central node. Reads\n// at 14×14 without shipping the full brand artwork. Uses currentColor\n// so the consumer can recolor it (CardHeader's vendor strip pipes the\n// HubSpot brand orange in via inline `style.color`).\n\nimport type { ReactNode } from \"react\";\nimport type { CardVendor } from \"@apteva/ui-kit\";\n\nexport const hubspotLogo: ReactNode = (\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden>\n <circle cx=\"18\" cy=\"6\" r=\"2.2\" />\n <circle cx=\"18\" cy=\"18\" r=\"2.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"2.2\" />\n <circle cx=\"14\" cy=\"12\" r=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" fill=\"none\" />\n </svg>\n);\n\n// HubSpot's official brand orange. Passed through CardHeader's\n// `vendor.color` so the brand strip on every HubSpot-emitted card\n// reads as obviously HubSpot at a glance, in both light and dark.\nexport const HUBSPOT_BRAND_COLOR = \"#FF7A59\";\n\nexport const hubspotVendor: CardVendor = {\n name: \"HubSpot\",\n logo: hubspotLogo,\n color: HUBSPOT_BRAND_COLOR,\n};\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "0AFC5D6EB6E2152964756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface DealRow {
|
|
2
|
+
deal_id: string;
|
|
3
|
+
dealname?: string;
|
|
4
|
+
amount?: string;
|
|
5
|
+
dealstage?: string;
|
|
6
|
+
dealstage_label?: string;
|
|
7
|
+
closedate?: string;
|
|
8
|
+
company_name?: string;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
items?: DealRow[];
|
|
12
|
+
/** Headline shown in the card header. */
|
|
13
|
+
title?: string;
|
|
14
|
+
/** Subtitle below the title — e.g."Open · sorted by close date". */
|
|
15
|
+
subtitle?: string;
|
|
16
|
+
/** Cap rendered rows; show"+N more" footer when exceeded. */
|
|
17
|
+
max_rows?: number;
|
|
18
|
+
portal_id?: string;
|
|
19
|
+
preview?: boolean;
|
|
20
|
+
projectId?: string;
|
|
21
|
+
}
|
|
22
|
+
export default function DealList(props: Props): import("react").JSX.Element;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=DealList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DealList.d.ts","sourceRoot":"","sources":["../../../src/ui/hubspot/DealList.tsx"],"names":[],"mappings":"AAOA,UAAU,OAAO;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,KAAK;IACd,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAUD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,KAAK,+BA6C5C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// DealList — dense rows of deals. Same field shape as DealCard but
|
|
2
|
+
// for the"show me my open deals" use case. Footer summarises count
|
|
3
|
+
// and total $ across all rows (not just the visible ones).
|
|
4
|
+
import { Card, CardHeader, StatusPill, Row } from "@apteva/ui-kit";
|
|
5
|
+
import { dealStageMeta, formatUSD, formatRelativeDate, recordUrl, addDaysISO, hubspotVendor } from "./lib/hubspot";
|
|
6
|
+
const previewItems = [
|
|
7
|
+
{ deal_id: "1", dealname: "Acme Q4 Renewal", amount: "48000", dealstage: "contractsent", closedate: addDaysISO(7), company_name: "Acme Logistics" },
|
|
8
|
+
{ deal_id: "2", dealname: "Globex Pilot", amount: "24000", dealstage: "presentationscheduled", closedate: addDaysISO(28), company_name: "Globex Innovations" },
|
|
9
|
+
{ deal_id: "3", dealname: "Initech Enterprise", amount: "120000", dealstage: "decisionmakerboughtin", closedate: addDaysISO(14), company_name: "Initech Corp" },
|
|
10
|
+
{ deal_id: "4", dealname: "Soylent Expansion", amount: "62000", dealstage: "qualifiedtobuy", closedate: addDaysISO(42), company_name: "Soylent Foods" },
|
|
11
|
+
{ deal_id: "5", dealname: "Hooli Multi-year", amount: "315000", dealstage: "decisionmakerboughtin", closedate: addDaysISO(21), company_name: "Hooli" },
|
|
12
|
+
];
|
|
13
|
+
export default function DealList(props) {
|
|
14
|
+
const items = props.preview ? (props.items ?? previewItems) : (props.items ?? []);
|
|
15
|
+
const max = props.max_rows ?? 6;
|
|
16
|
+
const visible = items.slice(0, max);
|
|
17
|
+
const overflow = items.length - visible.length;
|
|
18
|
+
const total = items.reduce((acc, d) => acc + (Number(d.amount ?? 0) || 0), 0);
|
|
19
|
+
return (<Card fullWidth>
|
|
20
|
+
<CardHeader vendor={hubspotVendor} title={props.title || "Deals"} subtitle={props.subtitle || (items.length > 0 ? `${items.length} deal${items.length === 1 ? "" : "s"} · ${formatUSD(total)} total` : "No deals")}/>
|
|
21
|
+
{visible.length === 0 && (<div className="px-3 py-3 text-xs text-text-dim">No deals match.</div>)}
|
|
22
|
+
{visible.map((d, i) => {
|
|
23
|
+
const stage = dealStageMeta(d.dealstage, d.dealstage_label);
|
|
24
|
+
return (<Row key={d.deal_id} flush={i === 0} href={recordUrl("deal", d.deal_id, props.portal_id)} title={d.dealname || `Deal ${d.deal_id}`} subtitle={d.company_name} trailing={<span className="inline-flex items-center gap-2">
|
|
25
|
+
<span className="tabular-nums text-text">{formatUSD(d.amount)}</span>
|
|
26
|
+
<StatusPill variant={stage.variant}>{stage.label}</StatusPill>
|
|
27
|
+
{d.closedate && (<span className="text-text-dim hidden sm:inline tabular-nums">{formatRelativeDate(d.closedate)}</span>)}
|
|
28
|
+
</span>}/>);
|
|
29
|
+
})}
|
|
30
|
+
{overflow > 0 && (<div className="px-3 py-1.5 text-[11px] text-text-dim border-t border-border">
|
|
31
|
+
+{overflow} more
|
|
32
|
+
</div>)}
|
|
33
|
+
</Card>);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=DealList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DealList.js","sourceRoot":"","sources":["../../../src/ui/hubspot/DealList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Card as R,CardHeader as b,StatusPill as k,Row as A}from"@apteva/ui-kit";import{jsx as V,jsxs as _}from"react/jsx-runtime";var P={appointmentscheduled:{label:"Appointment scheduled",variant:"info"},qualifiedtobuy:{label:"Qualified to buy",variant:"info"},presentationscheduled:{label:"Presentation scheduled",variant:"info"},decisionmakerboughtin:{label:"Decision-maker bought in ",variant:"info"},contractsent:{label:"Contract sent",variant:"warn"},closedwon:{label:"Closed (won)",variant:"success"},closedlost:{label:"Closed (lost)",variant:"error"}};function H(q,J){if(!q)return{label:J??"—",variant:"neutral"};let X=P[q];if(X)return{label:J??X.label,variant:X.variant};return{label:J??q,variant:"neutral"}}function N(q){if(q===void 0||q===null||q==="")return"—";let J=typeof q==="number"?q:Number(q);if(!Number.isFinite(J))return String(q);return J.toLocaleString("en-US",{style:"currency",currency:"USD",maximumFractionDigits:J>=1000?0:2})}function B(q){if(!q)return"—";let J=new Date(q);if(Number.isNaN(J.getTime()))return q;let X=new Date,W=Math.round((J.getTime()-X.getTime())/86400000),Z=J.toLocaleDateString("en-US",{month:"short",day:"numeric"});if(W===0)return`${Z} · today`;if(W>0)return`${Z} · in ${W} day${W===1?"":"s"}`;let z=-W;return`${Z} · ${z} day${z===1?"":"s"} overdue`}function $(q){let J=new Date;return J.setDate(J.getDate()+q),J.toISOString().slice(0,10)}var f="0";function K(q,J,X){return`https://app.hubspot.com/contacts/${X||f}/${q}/${J}`}var g=_("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:[V("circle",{cx:"18",cy:"6",r:"2.2"}),V("circle",{cx:"18",cy:"18",r:"2.2"}),V("circle",{cx:"6",cy:"12",r:"2.2"}),V("circle",{cx:"14",cy:"12",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.5"}),V("path",{d:"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8",stroke:"currentColor",strokeWidth:"1.2",fill:"none"})]}),E="#FF7A59",U={name:"HubSpot",logo:g,color:E};import{jsx as M,jsxs as Y}from"react/jsx-runtime";var C=[{deal_id:"1",dealname:"Acme Q4 Renewal",amount:"48000",dealstage:"contractsent",closedate:$(7),company_name:"Acme Logistics"},{deal_id:"2",dealname:"Globex Pilot",amount:"24000",dealstage:"presentationscheduled",closedate:$(28),company_name:"Globex Innovations"},{deal_id:"3",dealname:"Initech Enterprise",amount:"120000",dealstage:"decisionmakerboughtin",closedate:$(14),company_name:"Initech Corp"},{deal_id:"4",dealname:"Soylent Expansion",amount:"62000",dealstage:"qualifiedtobuy",closedate:$(42),company_name:"Soylent Foods"},{deal_id:"5",dealname:"Hooli Multi-year",amount:"315000",dealstage:"decisionmakerboughtin",closedate:$(21),company_name:"Hooli"}];function D(q){let J=q.preview?q.items??C:q.items??[],X=q.max_rows??6,W=J.slice(0,X),Z=J.length-W.length,z=J.reduce((Q,G)=>Q+(Number(G.amount??0)||0),0);return Y(R,{fullWidth:!0,children:[M(b,{vendor:U,title:q.title||"Deals",subtitle:q.subtitle||(J.length>0?`${J.length} deal${J.length===1?"":"s"} · ${N(z)} total`:"No deals")}),W.length===0&&M("div",{className:"px-3 py-3 text-xs text-text-dim",children:"No deals match."}),W.map((Q,G)=>{let F=H(Q.dealstage,Q.dealstage_label);return M(A,{flush:G===0,href:K("deal",Q.deal_id,q.portal_id),title:Q.dealname||`Deal ${Q.deal_id}`,subtitle:Q.company_name,trailing:Y("span",{className:"inline-flex items-center gap-2",children:[M("span",{className:"tabular-nums text-text",children:N(Q.amount)}),M(k,{variant:F.variant,children:F.label}),Q.closedate&&M("span",{className:"text-text-dim hidden sm:inline tabular-nums",children:B(Q.closedate)})]})},Q.deal_id)}),Z>0&&Y("div",{className:"px-3 py-1.5 text-[11px] text-text-dim border-t border-border",children:["+",Z," more"]})]})}export{D as default};
|
|
2
|
+
|
|
3
|
+
//# debugId=FAB856903A77290564756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ui/hubspot/DealList.tsx", "../../../src/ui/hubspot/lib/hubspot.tsx"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"// DealList — dense rows of deals. Same field shape as DealCard but\n// for the\"show me my open deals\" use case. Footer summarises count\n// and total $ across all rows (not just the visible ones).\n\nimport { Card, CardHeader, StatusPill, Row } from \"@apteva/ui-kit\";\nimport { dealStageMeta, formatUSD, formatRelativeDate, recordUrl, addDaysISO, hubspotVendor } from \"./lib/hubspot\";\n\ninterface DealRow {\n deal_id: string;\n dealname?: string;\n amount?: string;\n dealstage?: string;\n dealstage_label?: string;\n closedate?: string;\n company_name?: string;\n}\n\ninterface Props {\n items?: DealRow[];\n /** Headline shown in the card header. */\n title?: string;\n /** Subtitle below the title — e.g.\"Open · sorted by close date\". */\n subtitle?: string;\n /** Cap rendered rows; show\"+N more\" footer when exceeded. */\n max_rows?: number;\n portal_id?: string;\n preview?: boolean;\n projectId?: string;\n}\n\nconst previewItems: DealRow[] = [\n { deal_id: \"1\", dealname: \"Acme Q4 Renewal\", amount: \"48000\", dealstage: \"contractsent\", closedate: addDaysISO(7), company_name: \"Acme Logistics\" },\n { deal_id: \"2\", dealname: \"Globex Pilot\", amount: \"24000\", dealstage: \"presentationscheduled\", closedate: addDaysISO(28), company_name: \"Globex Innovations\" },\n { deal_id: \"3\", dealname: \"Initech Enterprise\", amount: \"120000\", dealstage: \"decisionmakerboughtin\", closedate: addDaysISO(14), company_name: \"Initech Corp\" },\n { deal_id: \"4\", dealname: \"Soylent Expansion\", amount: \"62000\", dealstage: \"qualifiedtobuy\", closedate: addDaysISO(42), company_name: \"Soylent Foods\" },\n { deal_id: \"5\", dealname: \"Hooli Multi-year\", amount: \"315000\", dealstage: \"decisionmakerboughtin\", closedate: addDaysISO(21), company_name: \"Hooli\" },\n];\n\nexport default function DealList(props: Props) {\n const items = props.preview ? (props.items ?? previewItems) : (props.items ?? []);\n const max = props.max_rows ?? 6;\n const visible = items.slice(0, max);\n const overflow = items.length - visible.length;\n const total = items.reduce((acc, d) => acc + (Number(d.amount ?? 0) || 0), 0);\n\n return (\n <Card fullWidth>\n <CardHeader\n vendor={hubspotVendor}\n title={props.title || \"Deals\"}\n subtitle={props.subtitle || (items.length > 0 ? `${items.length} deal${items.length === 1 ? \"\" :\"s\"} · ${formatUSD(total)} total` :\"No deals\")}\n />\n {visible.length === 0 && (\n <div className=\"px-3 py-3 text-xs text-text-dim\">No deals match.</div>\n )}\n {visible.map((d, i) => {\n const stage = dealStageMeta(d.dealstage, d.dealstage_label);\n return (\n <Row\n key={d.deal_id}\n flush={i === 0}\n href={recordUrl(\"deal\", d.deal_id, props.portal_id)}\n title={d.dealname || `Deal ${d.deal_id}`}\n subtitle={d.company_name}\n trailing={\n <span className=\"inline-flex items-center gap-2\">\n <span className=\"tabular-nums text-text\">{formatUSD(d.amount)}</span>\n <StatusPill variant={stage.variant}>{stage.label}</StatusPill>\n {d.closedate && (\n <span className=\"text-text-dim hidden sm:inline tabular-nums\">{formatRelativeDate(d.closedate)}</span>\n )}\n </span>\n }\n />\n );\n })}\n {overflow > 0 && (\n <div className=\"px-3 py-1.5 text-[11px] text-text-dim border-t border-border\">\n +{overflow} more\n </div>\n )}\n </Card>\n );\n}\n",
|
|
6
|
+
"// Shared helpers for every HubSpot UI component.\n//\n// * pill metadata for deal stages, ticket priorities, lifecycle\n// stages — one source of truth for label + color across cards\n// * formatters: USD, relative date, relative time-since\n// * URL builders for HubSpot canonical record links\n// * favicon helper (Google s2)\n// * pillToDot — bridges StatusPill variant → StatusDot variant for\n// CardHeader's status slot\n// * HubSpot brand mark SVG used in every card header\n\nimport type { StatusDotVariant, StatusPillVariant } from \"@apteva/ui-kit\";\n\n// ─── pill metadata ────────────────────────────────────────────────\n\nexport type PillMeta = { label: string; variant: StatusPillVariant };\n\nconst DEAL_STAGE: Record<string, PillMeta> = {\n appointmentscheduled: { label: \"Appointment scheduled\", variant: \"info\" },\n qualifiedtobuy: { label: \"Qualified to buy\", variant: \"info\" },\n presentationscheduled: { label: \"Presentation scheduled\", variant: \"info\" },\n decisionmakerboughtin: { label: \"Decision-maker bought in \", variant: \"info\" },\n contractsent: { label: \"Contract sent\", variant: \"warn\" },\n closedwon: { label: \"Closed (won)\", variant: \"success\" },\n closedlost: { label: \"Closed (lost)\", variant: \"error\" },\n};\n\nexport function dealStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = DEAL_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst TICKET_PRIORITY: Record<string, PillMeta> = {\n LOW: { label: \"Low\", variant: \"neutral\" },\n MEDIUM: { label: \"Medium\", variant: \"info\" },\n HIGH: { label: \"High\", variant: \"warn\" },\n URGENT: { label: \"Urgent\", variant: \"error\" },\n};\n\nexport function ticketPriorityMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return TICKET_PRIORITY[id] ?? { label: id, variant: \"neutral\" };\n}\n\nconst TICKET_STAGE: Record<string, PillMeta> = {\n \"1\": { label: \"New\", variant: \"info\" },\n \"2\": { label: \"Waiting on us\", variant: \"warn\" },\n \"3\": { label: \"Waiting on them\", variant: \"neutral\" },\n \"4\": { label: \"Closed\", variant: \"success\" },\n};\n\nexport function ticketStageMeta(id: string | undefined, override?: string): PillMeta {\n if (!id) return { label: override ?? \"—\", variant: \"neutral\" };\n const known = TICKET_STAGE[id];\n if (known) return { label: override ?? known.label, variant: known.variant };\n return { label: override ?? id, variant: \"neutral\" };\n}\n\nconst LIFECYCLE: Record<string, PillMeta> = {\n subscriber: { label: \"Subscriber\", variant: \"neutral\" },\n lead: { label: \"Lead\", variant: \"neutral\" },\n marketingqualifiedlead: { label: \"MQL\", variant: \"info\" },\n salesqualifiedlead: { label: \"SQL\", variant: \"info\" },\n opportunity: { label: \"Opportunity\", variant: \"info\" },\n customer: { label: \"Customer\", variant: \"success\" },\n evangelist: { label: \"Evangelist\", variant: \"success\" },\n other: { label: \"Other\", variant: \"neutral\" },\n};\n\nexport function lifecycleMeta(id: string | undefined): PillMeta {\n if (!id) return { label: \"—\", variant: \"neutral\" };\n return LIFECYCLE[id] ?? { label: id, variant: \"neutral\" };\n}\n\n// ─── formatters ───────────────────────────────────────────────────\n\nexport function formatUSD(raw: string | number | undefined | null): string {\n if (raw === undefined || raw === null || raw === \"\") return \"—\";\n const n = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(n)) return String(raw);\n return n.toLocaleString(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: n >= 1000 ? 0 : 2,\n });\n}\n\nexport function formatRelativeDate(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const now = new Date();\n const days = Math.round((d.getTime() - now.getTime()) / 86_400_000);\n const dateStr = d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n if (days === 0) return `${dateStr} · today`;\n if (days > 0) return `${dateStr} · in ${days} day${days === 1 ? \"\" : \"s\"}`;\n const overdue = -days;\n return `${dateStr} · ${overdue} day${overdue === 1 ? \"\" : \"s\"} overdue`;\n}\n\nexport function timeAgo(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n const sec = Math.round((Date.now() - d.getTime()) / 1000);\n if (sec < 60) return \"just now\";\n const min = Math.round(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.round(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.round(hr / 24);\n if (day < 7) return `${day}d ago`;\n const wk = Math.round(day / 7);\n if (wk < 5) return `${wk}w ago`;\n return d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n}\n\nexport function addDaysISO(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() + n);\n return d.toISOString().slice(0, 10);\n}\n\nexport function minusHoursISO(n: number): string {\n const d = new Date();\n d.setHours(d.getHours() - n);\n return d.toISOString();\n}\n\n// ─── URL builders ─────────────────────────────────────────────────\n\nconst PORTAL_FALLBACK = \"0\";\n\nexport function recordUrl(\n type: \"deal\" | \"company\" | \"contact\" | \"ticket\" | \"engagement\",\n id: string,\n portalId?: string,\n): string {\n const portal = portalId || PORTAL_FALLBACK;\n return `https://app.hubspot.com/contacts/${portal}/${type}/${id}`;\n}\n\nexport function pipelineUrl(portalId?: string, pipeline?: string): string {\n const portal = portalId || PORTAL_FALLBACK;\n const path = pipeline ? `?pipeline=${encodeURIComponent(pipeline)}` : \"\";\n return `https://app.hubspot.com/pipelines/${portal}/deals${path}`;\n}\n\n// ─── favicon helper ───────────────────────────────────────────────\n\nexport function faviconFor(domain: string | undefined, size = 32): string | undefined {\n if (!domain) return undefined;\n return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`;\n}\n\n// ─── pill → dot bridge ────────────────────────────────────────────\n//\n// CardHeader's status slot wants a StatusDot variant. StatusPill's\n// variant set is wider; this is the canonical mapping.\n\nexport function pillToDot(v: StatusPillVariant): StatusDotVariant {\n switch (v) {\n case \"success\": return \"live\";\n case \"info\": return \"active\";\n case \"warn\": return \"warn\";\n case \"error\": return \"error\";\n default: return \"muted\";\n }\n}\n\n// ─── HubSpot brand mark ───────────────────────────────────────────\n//\n// Simplified mark — three satellites linked to a central node. Reads\n// at 14×14 without shipping the full brand artwork. Uses currentColor\n// so the consumer can recolor it (CardHeader's vendor strip pipes the\n// HubSpot brand orange in via inline `style.color`).\n\nimport type { ReactNode } from \"react\";\nimport type { CardVendor } from \"@apteva/ui-kit\";\n\nexport const hubspotLogo: ReactNode = (\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden>\n <circle cx=\"18\" cy=\"6\" r=\"2.2\" />\n <circle cx=\"18\" cy=\"18\" r=\"2.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"2.2\" />\n <circle cx=\"14\" cy=\"12\" r=\"3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M8.2 12 L11 12 M16 7.5 L15 10.2 M16 16.5 L15 13.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" fill=\"none\" />\n </svg>\n);\n\n// HubSpot's official brand orange. Passed through CardHeader's\n// `vendor.color` so the brand strip on every HubSpot-emitted card\n// reads as obviously HubSpot at a glance, in both light and dark.\nexport const HUBSPOT_BRAND_COLOR = \"#FF7A59\";\n\nexport const hubspotVendor: CardVendor = {\n name: \"HubSpot\",\n logo: hubspotLogo,\n color: HUBSPOT_BRAND_COLOR,\n};\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "FAB856903A77290564756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|