@travories/frontend-sdk 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +308 -95
  2. package/package.json +7 -3
package/README.md CHANGED
@@ -1,66 +1,98 @@
1
- # @travories/sdk
1
+ # @travories/frontend-sdk
2
2
 
3
- Official Travories SDK. Fetch packages by slug and drop the full **Package Detail page** into any React app.
3
+ [![npm](https://img.shields.io/npm/v/@travories/frontend-sdk?color=cb3837&label=npm&logo=npm)](https://www.npmjs.com/package/@travories/frontend-sdk)
4
+ [![downloads](https://img.shields.io/npm/dm/@travories/frontend-sdk?color=blue)](https://www.npmjs.com/package/@travories/frontend-sdk)
5
+ [![types](https://img.shields.io/npm/types/@travories/frontend-sdk?logo=typescript&logoColor=white)](https://www.npmjs.com/package/@travories/frontend-sdk)
6
+ [![license](https://img.shields.io/npm/l/@travories/frontend-sdk?color=brightgreen)](./LICENSE)
4
7
 
5
- - Framework-agnostic API client (`TravoriesClient`)
6
- - React hooks (`usePackageBySlug`, `usePackageBundle`)
7
- - Self-contained UI component (`<PackageDetailView />`) with bundled styles — **no Tailwind required**
8
- - Full TypeScript types
9
- - ESM + CJS builds
8
+ > Official Travories SDK. Drop the full **package detail page** and **landing carousels** into any React app, or just use the API client to fetch packages on your own terms.
10
9
 
11
- ---
10
+ ```bash
11
+ npm install @travories/frontend-sdk
12
+ ```
12
13
 
13
- ## Install
14
+ ```tsx
15
+ import { TravoriesClient, PackageDetailView } from "@travories/frontend-sdk";
16
+ import "@travories/frontend-sdk/styles.css";
14
17
 
15
- ```bash
16
- npm install @travories/sdk
17
- # peer deps (only needed if you use the React component / hooks)
18
- npm install react react-dom
18
+ const client = new TravoriesClient({ baseUrl: "https://api.travories.com" });
19
+
20
+ export default function Page({ slug }: { slug: string }) {
21
+ return <PackageDetailView client={client} slug={slug} />;
22
+ }
19
23
  ```
20
24
 
25
+ That's a complete, production-grade package detail page: gallery, itinerary with map, day-by-day routes, booking sidebar, host card. ~95 KB gzipped.
26
+
21
27
  ---
22
28
 
23
- ## 1. Just the data
29
+ ## Features
24
30
 
25
- ```ts
26
- import { TravoriesClient } from "@travories/sdk";
31
+ - **Framework-agnostic API client** — fetch packages, hosts, routes, home sections. Works in Node, browser, Next.js server components, edge runtimes.
32
+ - **Drop-in pages** `<PackageDetailView />` for detail, `<HomeSections />` for landing. One prop and you're done.
33
+ - **Composable layouts** — `<HomeSectionsProvider>` + `<PackagesSection>` lets you interleave SDK sections with your own content (FAQs, banners, etc.), all sharing one fetch.
34
+ - **Real maps** — Leaflet-powered map with per-day GeoJSON routes flown to on day change.
35
+ - **Bundled styling** — Tailwind precompiled and scoped to `.tvr-package-detail`. No Tailwind required in your app, no class conflicts with your own.
36
+ - **Full TypeScript types** — every prop, every API response shape, ergonomic union types.
37
+ - **ESM + CJS + sourcemaps** — works with any bundler, any Node version ≥ 18.
38
+ - **SSR-first** — pass `initialBundle` / `initialSections` to skip client fetches and render on the server.
27
39
 
28
- const travories = new TravoriesClient({
29
- baseUrl: "https://api.travories.com",
30
- });
40
+ ---
31
41
 
32
- const pkg = await travories.packages.getBySlug("everest-base-camp");
33
- console.log(pkg?.title, pkg?.totalDays);
42
+ ## Contents
43
+
44
+ - [Install](#install)
45
+ - [Quick start](#quick-start)
46
+ - [Detail page](#detail-page)
47
+ - [Landing carousels](#landing-carousels)
48
+ - [Just the data](#just-the-data)
49
+ - [Components](#components)
50
+ - [Hooks](#hooks)
51
+ - [Client configuration](#client-configuration)
52
+ - [SSR with Next.js](#ssr-with-nextjs)
53
+ - [Composable landing layouts](#composable-landing-layouts)
54
+ - [Styling](#styling)
55
+ - [TypeScript](#typescript)
56
+ - [API reference](#api-reference)
57
+ - [Support](#support)
58
+ - [License](#license)
34
59
 
35
- // Or the convenience shortcut:
36
- const pkg2 = await travories.getPackageBySlug("everest-base-camp");
60
+ ---
37
61
 
38
- // Or fetch the full bundle (package + host + attractions) in one call:
39
- const bundle = await travories.getPackageBundle("everest-base-camp");
62
+ ## Install
63
+
64
+ ```bash
65
+ npm install @travories/frontend-sdk
66
+ ```
67
+
68
+ **Peer dependencies** (skip if you only use the API client):
69
+
70
+ ```bash
71
+ npm install react react-dom
40
72
  ```
41
73
 
42
- Returns `null` on 404 / network error (silent by default), or throws `TravoriesApiError` for unexpected statuses when not in silent mode.
74
+ Requires React 17+, Node 18+ (uses built-in `fetch`).
43
75
 
44
76
  ---
45
77
 
46
- ## 2. The drop-in component
78
+ ## Quick start
47
79
 
48
- `<PackageDetailView />` renders the whole detail page: gallery, overview, quick facts, itinerary, what's included / excluded / to pack, host card, and a sticky booking sidebar.
80
+ ### Detail page
49
81
 
50
82
  ```tsx
51
- import { TravoriesClient, PackageDetailView } from "@travories/sdk";
52
- import "@travories/sdk/styles.css"; // <- bundled styles
83
+ import { TravoriesClient, PackageDetailView } from "@travories/frontend-sdk";
84
+ import "@travories/frontend-sdk/styles.css";
53
85
 
54
86
  const client = new TravoriesClient({ baseUrl: "https://api.travories.com" });
55
87
 
56
- export default function PackagePage({ slug }: { slug: string }) {
88
+ function PackagePage({ slug }: { slug: string }) {
57
89
  return (
58
90
  <PackageDetailView
59
91
  client={client}
60
92
  slug={slug}
61
93
  currency="USD"
62
94
  onReserve={(pkg) => {
63
- // navigate to your booking flow
95
+ // hook your booking flow here
64
96
  window.location.href = `/checkout/${pkg.slug}`;
65
97
  }}
66
98
  />
@@ -68,126 +100,307 @@ export default function PackagePage({ slug }: { slug: string }) {
68
100
  }
69
101
  ```
70
102
 
71
- ### Props
103
+ ### Landing carousels
104
+
105
+ ```tsx
106
+ import { TravoriesClient, HomeSections } from "@travories/frontend-sdk";
107
+ import "@travories/frontend-sdk/styles.css";
108
+
109
+ const client = new TravoriesClient({ baseUrl: "https://api.travories.com" });
110
+
111
+ function Landing() {
112
+ return (
113
+ <HomeSections
114
+ client={client}
115
+ currency="USD"
116
+ hrefFor={(pkg) => `/package/${pkg.slug}`}
117
+ openInNewTab
118
+ />
119
+ );
120
+ }
121
+ ```
122
+
123
+ Renders the four canonical sections: **Popular**, **Trending Right Now**, **Top Rated**, **More to Explore**.
124
+
125
+ ### Just the data
126
+
127
+ ```ts
128
+ import { TravoriesClient } from "@travories/frontend-sdk";
129
+
130
+ const client = new TravoriesClient({ baseUrl: "https://api.travories.com" });
131
+
132
+ const pkg = await client.getPackageBySlug("everest-base-camp");
133
+ const bundle = await client.getPackageBundle("everest-base-camp");
134
+ // ↑ pkg + host + attractions + routes in one call
135
+ const sections = await client.packages.getHomeSections();
136
+ ```
137
+
138
+ No React, no UI — just typed data. Use in scripts, edge functions, Node servers, anywhere.
139
+
140
+ ---
141
+
142
+ ## Components
143
+
144
+ ### Page-level drop-ins
145
+
146
+ | Component | What it renders |
147
+ |---|---|
148
+ | `<PackageDetailView />` | Full detail page: gallery, overview, key facts, itinerary + map, included/excluded/to-pack, host. |
149
+ | `<HomeSections />` | All four landing sections in one block (one fetch). |
150
+ | `<HomeSectionsProvider />` | Fetches the four sections once, exposes via context. Wrap your tree to use `<PackagesSection>` anywhere inside. |
151
+ | `<PackagesSection section="trending" />` | One specific section (Popular / Trending / Top Rated / More to Explore). Drop multiple inside a Provider — they share one fetch. |
152
+
153
+ ### Composable sub-components
154
+
155
+ For custom layouts, every visual primitive is exported:
156
+
157
+ | Component | Purpose |
158
+ |---|---|
159
+ | `<PackagesCarousel />` | Horizontal scrollable strip with title + arrows. Pass your own list of packages. |
160
+ | `<PackageCard />` | Single card. Use in grids, masonry, anywhere. |
161
+ | `<TopSection />` | Detail-page header: breadcrumb, title, rating, gallery. |
162
+ | `<GallerySection />` | 5-image gallery grid + lightbox. |
163
+ | `<PackageOverview />` | Description + key facts panel. |
164
+ | `<Itinerary />` | Day tabs + day card + map (with FlyToBounds). |
165
+ | `<PackageMap />` | Leaflet wrapper with markers + GeoJSON polylines. |
166
+ | `<PackageIncluded />` | What's-included checklist. |
167
+ | `<PackageExcludedAndToPack />` | What's-excluded + what-to-pack lists. |
168
+ | `<HostCard />`, `<HostAbout />` | Host / agency card + about block. |
169
+ | `<BookingCardLite />` | Booking sidebar: date picker, traveler stepper, price math, Reserve CTA. |
170
+
171
+ ---
172
+
173
+ ## Hooks
174
+
175
+ For headless / build-your-own-UI consumers:
176
+
177
+ ```tsx
178
+ import { usePackageBundle, useHomeSections } from "@travories/frontend-sdk";
179
+
180
+ function Custom() {
181
+ const { data, loading, error, refetch } = usePackageBundle(client, slug);
182
+ // data: { pkg, host, attractions, routes }
183
+
184
+ const home = useHomeSections(client);
185
+ // home.data: { popular, trending, topRated, moreToExplore }
186
+
187
+ // ... render however you want
188
+ }
189
+ ```
190
+
191
+ | Hook | Returns |
192
+ |---|---|
193
+ | `usePackageBySlug(client, slug)` | `{ data: TravoriesPackage | null, loading, error, refetch }` |
194
+ | `usePackageBundle(client, slug)` | `{ data: PackageBundle | null, loading, error, refetch }` |
195
+ | `useHomeSections(client)` | `{ data: HomeSectionsResponse | null, loading, error, refetch }` |
196
+ | `useHomeSectionsContext()` | Same as above, but reads from `<HomeSectionsProvider>` context (one shared fetch). |
197
+
198
+ All hooks accept `null` instead of a client to stay inert (useful when you already have data via `initialBundle` / `initialSections`).
199
+
200
+ ---
201
+
202
+ ## Client configuration
203
+
204
+ ```ts
205
+ new TravoriesClient({
206
+ baseUrl: "https://api.travories.com", // required
207
+ apiKey: "tvr_xxx", // optional — sent as x-api-key
208
+ authToken: () => session?.accessToken, // optional — sent as Bearer
209
+ defaultHeaders: { "x-trace-id": "abc" }, // optional
210
+ fetchImpl: customFetch, // optional — supply your own fetch
211
+ });
212
+ ```
213
+
214
+ `authToken` accepts a string, a function, or an async function — useful when the token rotates.
72
215
 
73
- | Prop | Type | Notes |
74
- | --------------- | ------------------------------------- | ------------------------------------------------------------------------------------------- |
75
- | `client` | `TravoriesClient` | Required when using `slug`. |
76
- | `slug` | `string` | Package slug to fetch. |
77
- | `initialBundle` | `PackageBundle \| null` | Pre-fetched data. If set, no client-side fetch runs. Use this for SSR. |
78
- | `currency` | `string` | Default `"USD"`. Anything `Intl.NumberFormat` accepts. |
79
- | `onReserve` | `(pkg: TravoriesPackage) => void` | If omitted, the Reserve button shows a disabled "Contact host to book" state. |
80
- | `className` | `string` | Extra class on the root container. |
81
- | `renderLoading` | `() => ReactNode` | Override the loading skeleton. |
82
- | `renderNotFound`| `() => ReactNode` | Override the empty state. |
216
+ Errors fall back silently and return `null` by default. Pass `silent: false` per-call to throw `TravoriesApiError`:
83
217
 
84
- ### SSR example (Next.js App Router)
218
+ ```ts
219
+ import { TravoriesApiError } from "@travories/frontend-sdk";
220
+
221
+ try {
222
+ const pkg = await client.packages.getBySlug("missing", { silent: false });
223
+ } catch (err) {
224
+ if (err instanceof TravoriesApiError) {
225
+ console.error(err.status, err.url, err.body);
226
+ }
227
+ }
228
+ ```
229
+
230
+ ---
231
+
232
+ ## SSR with Next.js
233
+
234
+ The recommended pattern: fetch on the server, hand off via `initialBundle` / `initialSections`. The component skips its internal fetch and renders synchronously.
85
235
 
86
236
  ```tsx
87
237
  // app/packages/[slug]/page.tsx
88
- import { TravoriesClient, PackageDetailView } from "@travories/sdk";
89
- import "@travories/sdk/styles.css";
238
+ import { TravoriesClient, PackageDetailView } from "@travories/frontend-sdk";
239
+ import "@travories/frontend-sdk/styles.css";
90
240
 
91
241
  const client = new TravoriesClient({ baseUrl: process.env.TRAVORIES_API_URL! });
92
242
 
93
243
  export default async function Page({ params }: { params: { slug: string } }) {
94
244
  const bundle = await client.getPackageBundle(params.slug);
95
- if (!bundle) return <div>Not found</div>;
245
+ if (!bundle) return <NotFound />;
96
246
 
97
247
  return <PackageDetailView initialBundle={bundle} />;
98
248
  }
99
249
  ```
100
250
 
251
+ ```tsx
252
+ // app/page.tsx (landing)
253
+ import { TravoriesClient, HomeSections } from "@travories/frontend-sdk";
254
+ import "@travories/frontend-sdk/styles.css";
255
+
256
+ const client = new TravoriesClient({ baseUrl: process.env.TRAVORIES_API_URL! });
257
+
258
+ export default async function Landing() {
259
+ const sections = await client.packages.getHomeSections();
260
+ return (
261
+ <HomeSections
262
+ initialSections={sections}
263
+ hrefFor={(p) => `/package/${p.slug}`}
264
+ />
265
+ );
266
+ }
267
+ ```
268
+
269
+ Works with Pages Router (`getServerSideProps`), Remix loaders, and React Router data API too — the pattern is the same.
270
+
101
271
  ---
102
272
 
103
- ## 3. Hooks (build your own UI)
273
+ ## Composable landing layouts
274
+
275
+ When you want **SDK sections interleaved with your own content** (FAQs, testimonials, ads), wrap the page in `<HomeSectionsProvider>` and drop `<PackagesSection>` anywhere inside. Sections share one fetch.
104
276
 
105
277
  ```tsx
106
- import { TravoriesClient, usePackageBySlug } from "@travories/sdk";
278
+ import {
279
+ TravoriesClient,
280
+ HomeSectionsProvider,
281
+ PackagesSection,
282
+ } from "@travories/frontend-sdk";
107
283
 
108
284
  const client = new TravoriesClient({ baseUrl: "https://api.travories.com" });
109
285
 
110
- function MyPackage({ slug }: { slug: string }) {
111
- const { data, loading, error, refetch } = usePackageBySlug(client, slug);
286
+ function Landing() {
287
+ return (
288
+ <HomeSectionsProvider client={client}>
289
+ <Hero />
290
+ <PackagesSection section="popular" hrefFor={(p) => `/package/${p.slug}`} />
291
+ <PackagesSection section="trending" />
292
+ <FAQ /> {/* your own */}
293
+ <Newsletter /> {/* your own */}
294
+ <PackagesSection section="topRated" title="Editor's picks" />
295
+ <PackagesSection section="moreToExplore" />
296
+ <Footer />
297
+ </HomeSectionsProvider>
298
+ );
299
+ }
300
+ ```
112
301
 
113
- if (loading) return <p>Loading…</p>;
114
- if (error) return <p>{error.message}</p>;
115
- if (!data) return <p>Not found</p>;
302
+ Each section can override `title`, `subtitle`, `currency`, `onSelect`, `hrefFor`, `openInNewTab`, `hideWhenLoading`, `hideWhenEmpty`.
116
303
 
117
- return <h1>{data.title}</h1>;
304
+ For a totally custom block, drop down to `useHomeSectionsContext()`:
305
+
306
+ ```tsx
307
+ function StatsBar() {
308
+ const { data } = useHomeSectionsContext();
309
+ if (!data) return null;
310
+ return <div>{data.popular.length + data.trending.length} packages featured</div>;
118
311
  }
119
312
  ```
120
313
 
121
- `usePackageBundle(client, slug)` works the same way but returns `{ pkg, host, attractions }`.
122
-
123
314
  ---
124
315
 
125
- ## Client config
316
+ ## Styling
317
+
318
+ The SDK ships precompiled, scoped CSS:
126
319
 
127
320
  ```ts
128
- new TravoriesClient({
129
- baseUrl: "https://api.travories.com", // required
130
- apiKey: "tvr_xxx", // optional, sent as x-api-key
131
- authToken: () => session?.accessToken, // optional, sent as Bearer
132
- defaultHeaders: { "x-trace-id": "abc" }, // optional
133
- fetchImpl: customFetch, // optional, e.g. node-fetch in old Node
134
- });
321
+ import "@travories/frontend-sdk/styles.css";
135
322
  ```
136
323
 
137
- `authToken` accepts a string, a function, or an async function useful when the token is rotated.
324
+ **Scope guarantee**: all utility classes are scoped under `.tvr-package-detail` so they cannot collide with your own Tailwind setup. Your app's CSS is never affected.
325
+
326
+ **Re-skinning** — override the design tokens at the wrapper:
327
+
328
+ ```css
329
+ .tvr-package-detail {
330
+ /* CSS variables you can override */
331
+ --tvr-radius: 0.75rem;
332
+ }
333
+ ```
334
+
335
+ Tailwind tokens like `text-primary-normal` and `bg-secondary` remain customizable via standard CSS overrides if needed — the precompiled output is plain CSS.
138
336
 
139
337
  ---
140
338
 
141
339
  ## TypeScript
142
340
 
143
- All types are exported:
341
+ Every export ships with full type definitions. Notable types:
144
342
 
145
343
  ```ts
146
344
  import type {
345
+ // Domain
147
346
  TravoriesPackage,
148
- PackageHost,
149
347
  PackageBundle,
348
+ PackageHost,
150
349
  PackageDay,
151
350
  PackagePriceTier,
152
351
  PackageDiscount,
352
+ PackageRoute,
353
+ PackageRoutesDay,
354
+ HomePackageCard,
355
+ HomeSectionsResponse,
356
+ MajorAttractionItem,
153
357
  TravoriesImage,
154
- } from "@travories/sdk";
358
+
359
+ // Component props
360
+ PackageDetailViewProps,
361
+ HomeSectionsProps,
362
+ HomeSectionsProviderProps,
363
+ PackagesSectionProps,
364
+ HomeSectionKey,
365
+
366
+ // Hooks
367
+ UsePackageBySlugResult,
368
+ UsePackageBundleResult,
369
+ UseHomeSectionsResult,
370
+
371
+ // Errors
372
+ HttpClientConfig,
373
+ HttpRequestOptions,
374
+ } from "@travories/frontend-sdk";
155
375
  ```
156
376
 
157
377
  ---
158
378
 
159
- ## Styling
379
+ ## API reference
160
380
 
161
- The component ships with scoped CSS (every class is prefixed `tvr-`). Import it once:
381
+ ### `client.packages` methods
162
382
 
163
- ```ts
164
- import "@travories/sdk/styles.css";
165
- ```
383
+ | Method | Endpoint | Returns |
384
+ |---|---|---|
385
+ | `getBySlug(slug)` | `GET /agency-package/by-slug/:slug` | `TravoriesPackage \| null` |
386
+ | `getHost(slug)` | `GET /agency-info/by-package-slug/:slug` | `PackageHostResponse \| null` |
387
+ | `getMajorAttractions(slug)` | `GET /major-attractions/package/:slug` | `MajorAttractionsResponse \| null` |
388
+ | `getRoutes(slug)` | `GET /agency-package/routes/:slug` | `PackageRoutesResponse \| null` |
389
+ | `getHomeSections()` | `GET /agency-package/home/sections` | `HomeSectionsResponse \| null` |
390
+ | `getBundle(slug)` | parallel — combines the first four | `PackageBundle \| null` |
166
391
 
167
- CSS variables on `.tvr-root` let you re-skin without overriding individual selectors:
168
-
169
- ```css
170
- .tvr-root {
171
- --tvr-primary: #1d4ed8;
172
- --tvr-accent: #ec4899;
173
- --tvr-radius: 18px;
174
- }
175
- ```
392
+ Shortcut methods on the client itself: `client.getPackageBySlug(slug)`, `client.getPackageBundle(slug)`.
176
393
 
177
394
  ---
178
395
 
179
- ## Local development
396
+ ## Support
180
397
 
181
- ```bash
182
- cd sdk
183
- npm install
184
- npm run build # build to dist/
185
- npm run dev # watch mode
398
+ - **Docs / source**: [GitHub](https://github.com/Travories/frontend-sdk)
399
+ - **Issues / requests**: [github.com/Travories/frontend-sdk/issues](https://github.com/Travories/frontend-sdk/issues)
400
+ - **API**: [api.travories.com](https://api.travories.com)
186
401
 
187
- # example app
188
- cd example
189
- npm install
190
- npm run dev # http://localhost:5173
191
- ```
402
+ ---
403
+
404
+ ## License
192
405
 
193
- The example uses `"@travories/sdk": "file:.."` so any rebuild of the SDK is picked up immediately.
406
+ MIT © [Travories](https://travories.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travories/frontend-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Official Travories SDK — fetch packages by slug and render the full Travories package detail page in any React app.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -59,8 +59,12 @@
59
59
  "react-dom": ">=17"
60
60
  },
61
61
  "peerDependenciesMeta": {
62
- "react": { "optional": true },
63
- "react-dom": { "optional": true }
62
+ "react": {
63
+ "optional": true
64
+ },
65
+ "react-dom": {
66
+ "optional": true
67
+ }
64
68
  },
65
69
  "dependencies": {
66
70
  "@iconify/react": "^5.0.0",