@voyantjs/extras-react 0.2.0

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.
@@ -0,0 +1,14 @@
1
+ import type { z } from "zod";
2
+ export type VoyantFetcher = (url: string, init?: RequestInit) => Promise<Response>;
3
+ export declare const defaultFetcher: VoyantFetcher;
4
+ export declare class VoyantApiError extends Error {
5
+ readonly status: number;
6
+ readonly body: unknown;
7
+ constructor(message: string, status: number, body: unknown);
8
+ }
9
+ export interface FetchWithValidationOptions {
10
+ baseUrl: string;
11
+ fetcher: VoyantFetcher;
12
+ }
13
+ export declare function fetchWithValidation<TOut>(path: string, schema: z.ZodType<TOut>, options: FetchWithValidationOptions, init?: RequestInit): Promise<TOut>;
14
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAElF,eAAO,MAAM,cAAc,EAAE,aACoB,CAAA;AAEjD,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;gBAEV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D;AAaD,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,aAAa,CAAA;CACvB;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAC5C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EACvB,OAAO,EAAE,0BAA0B,EACnC,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
package/dist/client.js ADDED
@@ -0,0 +1,58 @@
1
+ export const defaultFetcher = (url, init) => fetch(url, { credentials: "include", ...init });
2
+ export class VoyantApiError extends Error {
3
+ status;
4
+ body;
5
+ constructor(message, status, body) {
6
+ super(message);
7
+ this.name = "VoyantApiError";
8
+ this.status = status;
9
+ this.body = body;
10
+ }
11
+ }
12
+ function extractErrorMessage(status, statusText, body) {
13
+ if (typeof body === "object" && body !== null && "error" in body) {
14
+ const err = body.error;
15
+ if (typeof err === "string")
16
+ return err;
17
+ if (typeof err === "object" && err !== null && "message" in err) {
18
+ return String(err.message);
19
+ }
20
+ }
21
+ return `Voyant API error: ${status} ${statusText}`;
22
+ }
23
+ export async function fetchWithValidation(path, schema, options, init) {
24
+ const url = joinUrl(options.baseUrl, path);
25
+ const headers = new Headers(init?.headers);
26
+ if (init?.body !== undefined && !headers.has("Content-Type")) {
27
+ headers.set("Content-Type", "application/json");
28
+ }
29
+ const response = await options.fetcher(url, { ...init, headers });
30
+ if (!response.ok) {
31
+ const body = await safeJson(response);
32
+ throw new VoyantApiError(extractErrorMessage(response.status, response.statusText, body), response.status, body);
33
+ }
34
+ if (response.status === 204)
35
+ return schema.parse(undefined);
36
+ const body = await safeJson(response);
37
+ const parsed = schema.safeParse(body);
38
+ if (!parsed.success) {
39
+ throw new VoyantApiError(`Voyant API response failed validation: ${parsed.error.message}`, response.status, body);
40
+ }
41
+ return parsed.data;
42
+ }
43
+ async function safeJson(response) {
44
+ const text = await response.text();
45
+ if (!text)
46
+ return undefined;
47
+ try {
48
+ return JSON.parse(text);
49
+ }
50
+ catch {
51
+ return text;
52
+ }
53
+ }
54
+ function joinUrl(baseUrl, path) {
55
+ const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
56
+ const trimmedPath = path.startsWith("/") ? path : `/${path}`;
57
+ return `${trimmedBase}${trimmedPath}`;
58
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./use-product-extra.js";
2
+ export * from "./use-product-extra-mutation.js";
3
+ export * from "./use-product-extras.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from "./use-product-extra.js";
2
+ export * from "./use-product-extra-mutation.js";
3
+ export * from "./use-product-extras.js";
@@ -0,0 +1,63 @@
1
+ import type { insertProductExtraSchema, updateProductExtraSchema } from "@voyantjs/extras";
2
+ import type { z } from "zod";
3
+ export type CreateProductExtraInput = z.input<typeof insertProductExtraSchema>;
4
+ export type UpdateProductExtraInput = z.input<typeof updateProductExtraSchema>;
5
+ export declare function useProductExtraMutation(): {
6
+ create: import("@tanstack/react-query").UseMutationResult<{
7
+ id: string;
8
+ productId: string;
9
+ code: string | null;
10
+ name: string;
11
+ description: string | null;
12
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
13
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
14
+ pricedPerPerson: boolean;
15
+ minQuantity: number | null;
16
+ maxQuantity: number | null;
17
+ defaultQuantity: number | null;
18
+ active: boolean;
19
+ sortOrder: number;
20
+ createdAt: string;
21
+ updatedAt: string;
22
+ metadata?: Record<string, unknown> | null | undefined;
23
+ }, Error, {
24
+ productId: string;
25
+ name: string;
26
+ code?: string | null | undefined;
27
+ description?: string | null | undefined;
28
+ selectionType?: "optional" | "required" | "default_selected" | "unavailable" | undefined;
29
+ pricingMode?: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free" | undefined;
30
+ pricedPerPerson?: boolean | undefined;
31
+ minQuantity?: number | null | undefined;
32
+ maxQuantity?: number | null | undefined;
33
+ defaultQuantity?: number | null | undefined;
34
+ active?: boolean | undefined;
35
+ sortOrder?: number | undefined;
36
+ metadata?: Record<string, unknown> | null | undefined;
37
+ }, unknown>;
38
+ update: import("@tanstack/react-query").UseMutationResult<{
39
+ id: string;
40
+ productId: string;
41
+ code: string | null;
42
+ name: string;
43
+ description: string | null;
44
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
45
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
46
+ pricedPerPerson: boolean;
47
+ minQuantity: number | null;
48
+ maxQuantity: number | null;
49
+ defaultQuantity: number | null;
50
+ active: boolean;
51
+ sortOrder: number;
52
+ createdAt: string;
53
+ updatedAt: string;
54
+ metadata?: Record<string, unknown> | null | undefined;
55
+ }, Error, {
56
+ id: string;
57
+ input: UpdateProductExtraInput;
58
+ }, unknown>;
59
+ remove: import("@tanstack/react-query").UseMutationResult<{
60
+ success: boolean;
61
+ }, Error, string, unknown>;
62
+ };
63
+ //# sourceMappingURL=use-product-extra-mutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-product-extra-mutation.d.ts","sourceRoot":"","sources":["../../src/hooks/use-product-extra-mutation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAO5B,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAC9E,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAE9E,wBAAgB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAqBK,MAAM;eAAS,uBAAuB;;;;;EA8BjF"}
@@ -0,0 +1,38 @@
1
+ "use client";
2
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
3
+ import { fetchWithValidation } from "../client.js";
4
+ import { useVoyantExtrasContext } from "../provider.js";
5
+ import { extrasQueryKeys } from "../query-keys.js";
6
+ import { productExtraSingleResponse, successEnvelope } from "../schemas.js";
7
+ export function useProductExtraMutation() {
8
+ const { baseUrl, fetcher } = useVoyantExtrasContext();
9
+ const queryClient = useQueryClient();
10
+ const create = useMutation({
11
+ mutationFn: async (input) => {
12
+ const { data } = await fetchWithValidation("/v1/extras/product-extras", productExtraSingleResponse, { baseUrl, fetcher }, { method: "POST", body: JSON.stringify(input) });
13
+ return data;
14
+ },
15
+ onSuccess: (data) => {
16
+ void queryClient.invalidateQueries({ queryKey: extrasQueryKeys.productExtras() });
17
+ queryClient.setQueryData(extrasQueryKeys.productExtra(data.id), data);
18
+ },
19
+ });
20
+ const update = useMutation({
21
+ mutationFn: async ({ id, input }) => {
22
+ const { data } = await fetchWithValidation(`/v1/extras/product-extras/${id}`, productExtraSingleResponse, { baseUrl, fetcher }, { method: "PATCH", body: JSON.stringify(input) });
23
+ return data;
24
+ },
25
+ onSuccess: (data) => {
26
+ void queryClient.invalidateQueries({ queryKey: extrasQueryKeys.productExtras() });
27
+ queryClient.setQueryData(extrasQueryKeys.productExtra(data.id), data);
28
+ },
29
+ });
30
+ const remove = useMutation({
31
+ mutationFn: async (id) => fetchWithValidation(`/v1/extras/product-extras/${id}`, successEnvelope, { baseUrl, fetcher }, { method: "DELETE" }),
32
+ onSuccess: (_data, id) => {
33
+ void queryClient.invalidateQueries({ queryKey: extrasQueryKeys.productExtras() });
34
+ queryClient.removeQueries({ queryKey: extrasQueryKeys.productExtra(id) });
35
+ },
36
+ });
37
+ return { create, update, remove };
38
+ }
@@ -0,0 +1,22 @@
1
+ export interface UseProductExtraOptions {
2
+ enabled?: boolean;
3
+ }
4
+ export declare function useProductExtra(id: string | null | undefined, options?: UseProductExtraOptions): import("@tanstack/react-query").UseQueryResult<{
5
+ id: string;
6
+ productId: string;
7
+ code: string | null;
8
+ name: string;
9
+ description: string | null;
10
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
11
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
12
+ pricedPerPerson: boolean;
13
+ minQuantity: number | null;
14
+ maxQuantity: number | null;
15
+ defaultQuantity: number | null;
16
+ active: boolean;
17
+ sortOrder: number;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ metadata?: Record<string, unknown> | null | undefined;
21
+ }, Error>;
22
+ //# sourceMappingURL=use-product-extra.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-product-extra.d.ts","sourceRoot":"","sources":["../../src/hooks/use-product-extra.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC7B,OAAO,GAAE,sBAA2B;;;;;;;;;;;;;;;;;UASrC"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { useVoyantExtrasContext } from "../provider.js";
4
+ import { getProductExtraQueryOptions } from "../query-options.js";
5
+ export function useProductExtra(id, options = {}) {
6
+ const { baseUrl, fetcher } = useVoyantExtrasContext();
7
+ const { enabled = true } = options;
8
+ return useQuery({
9
+ ...getProductExtraQueryOptions({ baseUrl, fetcher }, id ?? "__missing__"),
10
+ enabled: enabled && Boolean(id),
11
+ });
12
+ }
@@ -0,0 +1,28 @@
1
+ import type { ProductExtrasListFilters } from "../query-keys.js";
2
+ export interface UseProductExtrasOptions extends ProductExtrasListFilters {
3
+ enabled?: boolean;
4
+ }
5
+ export declare function useProductExtras(options?: UseProductExtrasOptions): import("@tanstack/react-query").UseQueryResult<{
6
+ data: {
7
+ id: string;
8
+ productId: string;
9
+ code: string | null;
10
+ name: string;
11
+ description: string | null;
12
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
13
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
14
+ pricedPerPerson: boolean;
15
+ minQuantity: number | null;
16
+ maxQuantity: number | null;
17
+ defaultQuantity: number | null;
18
+ active: boolean;
19
+ sortOrder: number;
20
+ createdAt: string;
21
+ updatedAt: string;
22
+ metadata?: Record<string, unknown> | null | undefined;
23
+ }[];
24
+ total: number;
25
+ limit: number;
26
+ offset: number;
27
+ }, Error>;
28
+ //# sourceMappingURL=use-product-extras.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-product-extras.d.ts","sourceRoot":"","sources":["../../src/hooks/use-product-extras.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAGhE,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B;;;;;;;;;;;;;;;;;;;;;;UAQrE"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { useVoyantExtrasContext } from "../provider.js";
4
+ import { getProductExtrasQueryOptions } from "../query-options.js";
5
+ export function useProductExtras(options = {}) {
6
+ const { baseUrl, fetcher } = useVoyantExtrasContext();
7
+ const { enabled = true, ...filters } = options;
8
+ return useQuery({
9
+ ...getProductExtrasQueryOptions({ baseUrl, fetcher }, filters),
10
+ enabled,
11
+ });
12
+ }
@@ -0,0 +1,7 @@
1
+ export { defaultFetcher, fetchWithValidation, VoyantApiError, type VoyantFetcher, } from "./client.js";
2
+ export * from "./hooks/index.js";
3
+ export { useVoyantExtrasContext, type VoyantExtrasContextValue, VoyantExtrasProvider, type VoyantExtrasProviderProps, } from "./provider.js";
4
+ export { extrasQueryKeys, type ProductExtrasListFilters } from "./query-keys.js";
5
+ export { getProductExtraQueryOptions, getProductExtrasQueryOptions } from "./query-options.js";
6
+ export * from "./schemas.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,KAAK,aAAa,GACnB,MAAM,aAAa,CAAA;AACpB,cAAc,kBAAkB,CAAA;AAChC,OAAO,EACL,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,oBAAoB,EACpB,KAAK,yBAAyB,GAC/B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,eAAe,EAAE,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AAC9F,cAAc,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { defaultFetcher, fetchWithValidation, VoyantApiError, } from "./client.js";
2
+ export * from "./hooks/index.js";
3
+ export { useVoyantExtrasContext, VoyantExtrasProvider, } from "./provider.js";
4
+ export { extrasQueryKeys } from "./query-keys.js";
5
+ export { getProductExtraQueryOptions, getProductExtrasQueryOptions } from "./query-options.js";
6
+ export * from "./schemas.js";
@@ -0,0 +1,2 @@
1
+ export { useVoyantReactContext as useVoyantExtrasContext, type VoyantReactContextValue as VoyantExtrasContextValue, VoyantReactProvider as VoyantExtrasProvider, type VoyantReactProviderProps as VoyantExtrasProviderProps, } from "@voyantjs/react";
2
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,IAAI,sBAAsB,EAC/C,KAAK,uBAAuB,IAAI,wBAAwB,EACxD,mBAAmB,IAAI,oBAAoB,EAC3C,KAAK,wBAAwB,IAAI,yBAAyB,GAC3D,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1 @@
1
+ export { useVoyantReactContext as useVoyantExtrasContext, VoyantReactProvider as VoyantExtrasProvider, } from "@voyantjs/react";
@@ -0,0 +1,14 @@
1
+ export interface ProductExtrasListFilters {
2
+ productId?: string | undefined;
3
+ active?: boolean | undefined;
4
+ search?: string | undefined;
5
+ limit?: number | undefined;
6
+ offset?: number | undefined;
7
+ }
8
+ export declare const extrasQueryKeys: {
9
+ readonly all: readonly ["voyant", "extras"];
10
+ readonly productExtras: () => readonly ["voyant", "extras", "product-extras"];
11
+ readonly productExtrasList: (filters: ProductExtrasListFilters) => readonly ["voyant", "extras", "product-extras", "list", ProductExtrasListFilters];
12
+ readonly productExtra: (id: string) => readonly ["voyant", "extras", "product-extras", "detail", string];
13
+ };
14
+ //# sourceMappingURL=query-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-keys.d.ts","sourceRoot":"","sources":["../src/query-keys.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,eAAO,MAAM,eAAe;;;0CAIG,wBAAwB;gCAElC,MAAM;CACjB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export const extrasQueryKeys = {
2
+ all: ["voyant", "extras"],
3
+ productExtras: () => [...extrasQueryKeys.all, "product-extras"],
4
+ productExtrasList: (filters) => [...extrasQueryKeys.productExtras(), "list", filters],
5
+ productExtra: (id) => [...extrasQueryKeys.productExtras(), "detail", id],
6
+ };
@@ -0,0 +1,175 @@
1
+ import { type FetchWithValidationOptions } from "./client.js";
2
+ import type { UseProductExtrasOptions } from "./hooks/use-product-extras.js";
3
+ export declare function getProductExtrasQueryOptions(client: FetchWithValidationOptions, options?: UseProductExtrasOptions): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
4
+ data: {
5
+ id: string;
6
+ productId: string;
7
+ code: string | null;
8
+ name: string;
9
+ description: string | null;
10
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
11
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
12
+ pricedPerPerson: boolean;
13
+ minQuantity: number | null;
14
+ maxQuantity: number | null;
15
+ defaultQuantity: number | null;
16
+ active: boolean;
17
+ sortOrder: number;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ metadata?: Record<string, unknown> | null | undefined;
21
+ }[];
22
+ total: number;
23
+ limit: number;
24
+ offset: number;
25
+ }, Error, {
26
+ data: {
27
+ id: string;
28
+ productId: string;
29
+ code: string | null;
30
+ name: string;
31
+ description: string | null;
32
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
33
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
34
+ pricedPerPerson: boolean;
35
+ minQuantity: number | null;
36
+ maxQuantity: number | null;
37
+ defaultQuantity: number | null;
38
+ active: boolean;
39
+ sortOrder: number;
40
+ createdAt: string;
41
+ updatedAt: string;
42
+ metadata?: Record<string, unknown> | null | undefined;
43
+ }[];
44
+ total: number;
45
+ limit: number;
46
+ offset: number;
47
+ }, readonly ["voyant", "extras", "product-extras", "list", import("./query-keys.js").ProductExtrasListFilters]>, "queryFn"> & {
48
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
49
+ data: {
50
+ id: string;
51
+ productId: string;
52
+ code: string | null;
53
+ name: string;
54
+ description: string | null;
55
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
56
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
57
+ pricedPerPerson: boolean;
58
+ minQuantity: number | null;
59
+ maxQuantity: number | null;
60
+ defaultQuantity: number | null;
61
+ active: boolean;
62
+ sortOrder: number;
63
+ createdAt: string;
64
+ updatedAt: string;
65
+ metadata?: Record<string, unknown> | null | undefined;
66
+ }[];
67
+ total: number;
68
+ limit: number;
69
+ offset: number;
70
+ }, readonly ["voyant", "extras", "product-extras", "list", import("./query-keys.js").ProductExtrasListFilters], never> | undefined;
71
+ } & {
72
+ queryKey: readonly ["voyant", "extras", "product-extras", "list", import("./query-keys.js").ProductExtrasListFilters] & {
73
+ [dataTagSymbol]: {
74
+ data: {
75
+ id: string;
76
+ productId: string;
77
+ code: string | null;
78
+ name: string;
79
+ description: string | null;
80
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
81
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
82
+ pricedPerPerson: boolean;
83
+ minQuantity: number | null;
84
+ maxQuantity: number | null;
85
+ defaultQuantity: number | null;
86
+ active: boolean;
87
+ sortOrder: number;
88
+ createdAt: string;
89
+ updatedAt: string;
90
+ metadata?: Record<string, unknown> | null | undefined;
91
+ }[];
92
+ total: number;
93
+ limit: number;
94
+ offset: number;
95
+ };
96
+ [dataTagErrorSymbol]: Error;
97
+ };
98
+ };
99
+ export declare function getProductExtraQueryOptions(client: FetchWithValidationOptions, id: string): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
100
+ id: string;
101
+ productId: string;
102
+ code: string | null;
103
+ name: string;
104
+ description: string | null;
105
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
106
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
107
+ pricedPerPerson: boolean;
108
+ minQuantity: number | null;
109
+ maxQuantity: number | null;
110
+ defaultQuantity: number | null;
111
+ active: boolean;
112
+ sortOrder: number;
113
+ createdAt: string;
114
+ updatedAt: string;
115
+ metadata?: Record<string, unknown> | null | undefined;
116
+ }, Error, {
117
+ id: string;
118
+ productId: string;
119
+ code: string | null;
120
+ name: string;
121
+ description: string | null;
122
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
123
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
124
+ pricedPerPerson: boolean;
125
+ minQuantity: number | null;
126
+ maxQuantity: number | null;
127
+ defaultQuantity: number | null;
128
+ active: boolean;
129
+ sortOrder: number;
130
+ createdAt: string;
131
+ updatedAt: string;
132
+ metadata?: Record<string, unknown> | null | undefined;
133
+ }, readonly ["voyant", "extras", "product-extras", "detail", string]>, "queryFn"> & {
134
+ queryFn?: import("@tanstack/react-query").QueryFunction<{
135
+ id: string;
136
+ productId: string;
137
+ code: string | null;
138
+ name: string;
139
+ description: string | null;
140
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
141
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
142
+ pricedPerPerson: boolean;
143
+ minQuantity: number | null;
144
+ maxQuantity: number | null;
145
+ defaultQuantity: number | null;
146
+ active: boolean;
147
+ sortOrder: number;
148
+ createdAt: string;
149
+ updatedAt: string;
150
+ metadata?: Record<string, unknown> | null | undefined;
151
+ }, readonly ["voyant", "extras", "product-extras", "detail", string], never> | undefined;
152
+ } & {
153
+ queryKey: readonly ["voyant", "extras", "product-extras", "detail", string] & {
154
+ [dataTagSymbol]: {
155
+ id: string;
156
+ productId: string;
157
+ code: string | null;
158
+ name: string;
159
+ description: string | null;
160
+ selectionType: "optional" | "required" | "default_selected" | "unavailable";
161
+ pricingMode: "included" | "per_person" | "per_booking" | "quantity_based" | "on_request" | "free";
162
+ pricedPerPerson: boolean;
163
+ minQuantity: number | null;
164
+ maxQuantity: number | null;
165
+ defaultQuantity: number | null;
166
+ active: boolean;
167
+ sortOrder: number;
168
+ createdAt: string;
169
+ updatedAt: string;
170
+ metadata?: Record<string, unknown> | null | undefined;
171
+ };
172
+ [dataTagErrorSymbol]: Error;
173
+ };
174
+ };
175
+ //# sourceMappingURL=query-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-options.d.ts","sourceRoot":"","sources":["../src/query-options.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,aAAa,CAAA;AAClF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA;AAI5E,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,0BAA0B,EAClC,OAAO,GAAE,uBAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtC;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,0BAA0B,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYzF"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { queryOptions } from "@tanstack/react-query";
3
+ import { fetchWithValidation } from "./client.js";
4
+ import { extrasQueryKeys } from "./query-keys.js";
5
+ import { productExtraListResponse, productExtraSingleResponse } from "./schemas.js";
6
+ export function getProductExtrasQueryOptions(client, options = {}) {
7
+ const { enabled: _enabled = true, ...filters } = options;
8
+ return queryOptions({
9
+ queryKey: extrasQueryKeys.productExtrasList(filters),
10
+ queryFn: () => {
11
+ const params = new URLSearchParams();
12
+ if (filters.productId)
13
+ params.set("productId", filters.productId);
14
+ if (filters.active !== undefined)
15
+ params.set("active", String(filters.active));
16
+ if (filters.search)
17
+ params.set("search", filters.search);
18
+ if (filters.limit !== undefined)
19
+ params.set("limit", String(filters.limit));
20
+ if (filters.offset !== undefined)
21
+ params.set("offset", String(filters.offset));
22
+ const qs = params.toString();
23
+ return fetchWithValidation(`/v1/extras/product-extras${qs ? `?${qs}` : ""}`, productExtraListResponse, client);
24
+ },
25
+ });
26
+ }
27
+ export function getProductExtraQueryOptions(client, id) {
28
+ return queryOptions({
29
+ queryKey: extrasQueryKeys.productExtra(id),
30
+ queryFn: async () => {
31
+ const { data } = await fetchWithValidation(`/v1/extras/product-extras/${id}`, productExtraSingleResponse, client);
32
+ return data;
33
+ },
34
+ });
35
+ }
@@ -0,0 +1,112 @@
1
+ import { z } from "zod";
2
+ export declare const paginatedEnvelope: <T extends z.ZodTypeAny>(item: T) => z.ZodObject<{
3
+ data: z.ZodArray<T>;
4
+ total: z.ZodNumber;
5
+ limit: z.ZodNumber;
6
+ offset: z.ZodNumber;
7
+ }, z.core.$strip>;
8
+ export declare const singleEnvelope: <T extends z.ZodTypeAny>(item: T) => z.ZodObject<{
9
+ data: T;
10
+ }, z.core.$strip>;
11
+ export declare const successEnvelope: z.ZodObject<{
12
+ success: z.ZodBoolean;
13
+ }, z.core.$strip>;
14
+ export declare const productExtraRecordSchema: z.ZodObject<{
15
+ id: z.ZodString;
16
+ productId: z.ZodString;
17
+ code: z.ZodNullable<z.ZodString>;
18
+ name: z.ZodString;
19
+ description: z.ZodNullable<z.ZodString>;
20
+ selectionType: z.ZodEnum<{
21
+ optional: "optional";
22
+ required: "required";
23
+ default_selected: "default_selected";
24
+ unavailable: "unavailable";
25
+ }>;
26
+ pricingMode: z.ZodEnum<{
27
+ included: "included";
28
+ per_person: "per_person";
29
+ per_booking: "per_booking";
30
+ quantity_based: "quantity_based";
31
+ on_request: "on_request";
32
+ free: "free";
33
+ }>;
34
+ pricedPerPerson: z.ZodBoolean;
35
+ minQuantity: z.ZodNullable<z.ZodNumber>;
36
+ maxQuantity: z.ZodNullable<z.ZodNumber>;
37
+ defaultQuantity: z.ZodNullable<z.ZodNumber>;
38
+ active: z.ZodBoolean;
39
+ sortOrder: z.ZodNumber;
40
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
41
+ createdAt: z.ZodString;
42
+ updatedAt: z.ZodString;
43
+ }, z.core.$strip>;
44
+ export type ProductExtraRecord = z.infer<typeof productExtraRecordSchema>;
45
+ export declare const productExtraListResponse: z.ZodObject<{
46
+ data: z.ZodArray<z.ZodObject<{
47
+ id: z.ZodString;
48
+ productId: z.ZodString;
49
+ code: z.ZodNullable<z.ZodString>;
50
+ name: z.ZodString;
51
+ description: z.ZodNullable<z.ZodString>;
52
+ selectionType: z.ZodEnum<{
53
+ optional: "optional";
54
+ required: "required";
55
+ default_selected: "default_selected";
56
+ unavailable: "unavailable";
57
+ }>;
58
+ pricingMode: z.ZodEnum<{
59
+ included: "included";
60
+ per_person: "per_person";
61
+ per_booking: "per_booking";
62
+ quantity_based: "quantity_based";
63
+ on_request: "on_request";
64
+ free: "free";
65
+ }>;
66
+ pricedPerPerson: z.ZodBoolean;
67
+ minQuantity: z.ZodNullable<z.ZodNumber>;
68
+ maxQuantity: z.ZodNullable<z.ZodNumber>;
69
+ defaultQuantity: z.ZodNullable<z.ZodNumber>;
70
+ active: z.ZodBoolean;
71
+ sortOrder: z.ZodNumber;
72
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
73
+ createdAt: z.ZodString;
74
+ updatedAt: z.ZodString;
75
+ }, z.core.$strip>>;
76
+ total: z.ZodNumber;
77
+ limit: z.ZodNumber;
78
+ offset: z.ZodNumber;
79
+ }, z.core.$strip>;
80
+ export declare const productExtraSingleResponse: z.ZodObject<{
81
+ data: z.ZodObject<{
82
+ id: z.ZodString;
83
+ productId: z.ZodString;
84
+ code: z.ZodNullable<z.ZodString>;
85
+ name: z.ZodString;
86
+ description: z.ZodNullable<z.ZodString>;
87
+ selectionType: z.ZodEnum<{
88
+ optional: "optional";
89
+ required: "required";
90
+ default_selected: "default_selected";
91
+ unavailable: "unavailable";
92
+ }>;
93
+ pricingMode: z.ZodEnum<{
94
+ included: "included";
95
+ per_person: "per_person";
96
+ per_booking: "per_booking";
97
+ quantity_based: "quantity_based";
98
+ on_request: "on_request";
99
+ free: "free";
100
+ }>;
101
+ pricedPerPerson: z.ZodBoolean;
102
+ minQuantity: z.ZodNullable<z.ZodNumber>;
103
+ maxQuantity: z.ZodNullable<z.ZodNumber>;
104
+ defaultQuantity: z.ZodNullable<z.ZodNumber>;
105
+ active: z.ZodBoolean;
106
+ sortOrder: z.ZodNumber;
107
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
108
+ createdAt: z.ZodString;
109
+ updatedAt: z.ZodString;
110
+ }, z.core.$strip>;
111
+ }, z.core.$strip>;
112
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC;;;;;iBAM7D,CAAA;AAEJ,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC;;iBAA6B,CAAA;AAC3F,eAAO,MAAM,eAAe;;iBAAqC,CAAA;AAEjE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwBnC,CAAA;AAEF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAEzE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2C,CAAA"}
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ export const paginatedEnvelope = (item) => z.object({
3
+ data: z.array(item),
4
+ total: z.number().int(),
5
+ limit: z.number().int(),
6
+ offset: z.number().int(),
7
+ });
8
+ export const singleEnvelope = (item) => z.object({ data: item });
9
+ export const successEnvelope = z.object({ success: z.boolean() });
10
+ export const productExtraRecordSchema = z.object({
11
+ id: z.string(),
12
+ productId: z.string(),
13
+ code: z.string().nullable(),
14
+ name: z.string(),
15
+ description: z.string().nullable(),
16
+ selectionType: z.enum(["optional", "required", "default_selected", "unavailable"]),
17
+ pricingMode: z.enum([
18
+ "included",
19
+ "per_person",
20
+ "per_booking",
21
+ "quantity_based",
22
+ "on_request",
23
+ "free",
24
+ ]),
25
+ pricedPerPerson: z.boolean(),
26
+ minQuantity: z.number().int().nullable(),
27
+ maxQuantity: z.number().int().nullable(),
28
+ defaultQuantity: z.number().int().nullable(),
29
+ active: z.boolean(),
30
+ sortOrder: z.number().int(),
31
+ metadata: z.record(z.string(), z.unknown()).nullable().optional(),
32
+ createdAt: z.string(),
33
+ updatedAt: z.string(),
34
+ });
35
+ export const productExtraListResponse = paginatedEnvelope(productExtraRecordSchema);
36
+ export const productExtraSingleResponse = singleEnvelope(productExtraRecordSchema);
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@voyantjs/extras-react",
3
+ "version": "0.2.0",
4
+ "license": "FSL-1.1-Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/voyantjs/voyant.git",
8
+ "directory": "packages/extras-react"
9
+ },
10
+ "type": "module",
11
+ "exports": {
12
+ ".": "./src/index.ts",
13
+ "./provider": "./src/provider.tsx",
14
+ "./hooks": "./src/hooks/index.ts",
15
+ "./client": "./src/client.ts",
16
+ "./query-keys": "./src/query-keys.ts"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.json",
20
+ "clean": "rm -rf dist",
21
+ "prepack": "pnpm run build",
22
+ "typecheck": "tsc --noEmit",
23
+ "lint": "biome check src/",
24
+ "test": "vitest run --passWithNoTests"
25
+ },
26
+ "peerDependencies": {
27
+ "@voyantjs/extras": "workspace:*",
28
+ "@tanstack/react-query": "^5.0.0",
29
+ "react": "^19.0.0",
30
+ "react-dom": "^19.0.0",
31
+ "zod": "^4.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@tanstack/react-query": "^5.96.2",
35
+ "@types/react": "^19.2.14",
36
+ "@types/react-dom": "^19.2.3",
37
+ "@voyantjs/extras": "workspace:*",
38
+ "@voyantjs/react": "workspace:*",
39
+ "@voyantjs/voyant-typescript-config": "workspace:*",
40
+ "react": "^19.2.4",
41
+ "react-dom": "^19.2.4",
42
+ "typescript": "^6.0.2",
43
+ "vitest": "^4.1.2",
44
+ "zod": "^4.3.6"
45
+ },
46
+ "dependencies": {
47
+ "@voyantjs/react": "workspace:*"
48
+ },
49
+ "files": [
50
+ "dist"
51
+ ],
52
+ "publishConfig": {
53
+ "access": "public",
54
+ "exports": {
55
+ ".": {
56
+ "types": "./dist/index.d.ts",
57
+ "import": "./dist/index.js"
58
+ },
59
+ "./provider": {
60
+ "types": "./dist/provider.d.ts",
61
+ "import": "./dist/provider.js"
62
+ },
63
+ "./hooks": {
64
+ "types": "./dist/hooks/index.d.ts",
65
+ "import": "./dist/hooks/index.js"
66
+ },
67
+ "./client": {
68
+ "types": "./dist/client.d.ts",
69
+ "import": "./dist/client.js"
70
+ },
71
+ "./query-keys": {
72
+ "types": "./dist/query-keys.d.ts",
73
+ "import": "./dist/query-keys.js"
74
+ }
75
+ },
76
+ "main": "./dist/index.js",
77
+ "types": "./dist/index.d.ts"
78
+ }
79
+ }