@htlkg/data 0.0.18 → 0.0.20

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 (38) hide show
  1. package/dist/client/index.d.ts +257 -1
  2. package/dist/client/index.js +59 -1
  3. package/dist/client/index.js.map +1 -1
  4. package/dist/common-DSxswsZ3.d.ts +40 -0
  5. package/dist/hooks/index.d.ts +75 -9
  6. package/dist/hooks/index.js +135 -35
  7. package/dist/hooks/index.js.map +1 -1
  8. package/dist/index.d.ts +6 -3
  9. package/dist/index.js +355 -15
  10. package/dist/index.js.map +1 -1
  11. package/dist/mutations/index.d.ts +17 -12
  12. package/dist/mutations/index.js +204 -2
  13. package/dist/mutations/index.js.map +1 -1
  14. package/dist/{productInstances-3LDgCZSO.d.ts → productInstances-BpQv1oLS.d.ts} +3 -7
  15. package/dist/queries/index.d.ts +3 -0
  16. package/dist/queries/index.js +82 -0
  17. package/dist/queries/index.js.map +1 -1
  18. package/dist/reservations-C0FNm__0.d.ts +154 -0
  19. package/dist/reservations-CdDfkcZ_.d.ts +172 -0
  20. package/package.json +3 -3
  21. package/src/client/index.ts +18 -0
  22. package/src/client/reservations.ts +336 -0
  23. package/src/hooks/createDataHook.test.ts +534 -0
  24. package/src/hooks/createDataHook.ts +20 -13
  25. package/src/hooks/index.ts +1 -0
  26. package/src/hooks/useReservations.ts +145 -0
  27. package/src/mutations/accounts.ts +5 -2
  28. package/src/mutations/brands.ts +5 -4
  29. package/src/mutations/common.ts +41 -0
  30. package/src/mutations/index.ts +22 -0
  31. package/src/mutations/productInstances/productInstances.test.ts +3 -3
  32. package/src/mutations/productInstances/productInstances.ts +7 -9
  33. package/src/mutations/reservations.test.ts +459 -0
  34. package/src/mutations/reservations.ts +452 -0
  35. package/src/mutations/users.ts +5 -4
  36. package/src/queries/index.ts +11 -0
  37. package/src/queries/reservations.test.ts +374 -0
  38. package/src/queries/reservations.ts +247 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * useReservations Hook
3
+ *
4
+ * Vue composable for fetching and managing reservation data with reactive state.
5
+ * Provides loading states, error handling, pagination, and refetch capabilities.
6
+ */
7
+
8
+ import type { Ref, ComputedRef } from "vue";
9
+ import type { Reservation } from "../queries/reservations";
10
+ import { createDataHook, type BaseHookOptions } from "./createDataHook";
11
+
12
+ export interface UseReservationsOptions extends BaseHookOptions {
13
+ /** Filter by brand ID */
14
+ brandId?: string;
15
+ /** Filter by start date (check-in date >= startDate) */
16
+ startDate?: string;
17
+ /** Filter by end date (check-in date <= endDate) */
18
+ endDate?: string;
19
+ /** Filter by reservation status */
20
+ status?: Reservation["status"];
21
+ /** Filter by contact/visit ID */
22
+ contactId?: string;
23
+ /** Pagination token for fetching next page */
24
+ nextToken?: string;
25
+ }
26
+
27
+ export interface UseReservationsReturn {
28
+ /** Reactive array of reservations */
29
+ reservations: Ref<Reservation[]>;
30
+ /** Computed array of confirmed reservations */
31
+ confirmedReservations: ComputedRef<Reservation[]>;
32
+ /** Computed array of active reservations (confirmed or checked_in) */
33
+ activeReservations: ComputedRef<Reservation[]>;
34
+ /** Loading state */
35
+ loading: Ref<boolean>;
36
+ /** Error state */
37
+ error: Ref<Error | null>;
38
+ /** Refetch reservations */
39
+ refetch: () => Promise<void>;
40
+ }
41
+
42
+ /**
43
+ * Build filter from hook options
44
+ */
45
+ function buildFilter(options: UseReservationsOptions): any {
46
+ const conditions: any[] = [];
47
+
48
+ if (options.brandId) {
49
+ conditions.push({ brandId: { eq: options.brandId } });
50
+ }
51
+
52
+ if (options.status) {
53
+ conditions.push({ status: { eq: options.status } });
54
+ }
55
+
56
+ if (options.contactId) {
57
+ conditions.push({ visitId: { eq: options.contactId } });
58
+ }
59
+
60
+ if (options.startDate) {
61
+ conditions.push({ checkIn: { ge: options.startDate } });
62
+ }
63
+
64
+ if (options.endDate) {
65
+ conditions.push({ checkIn: { le: options.endDate } });
66
+ }
67
+
68
+ if (options.filter) {
69
+ conditions.push(options.filter);
70
+ }
71
+
72
+ if (conditions.length === 0) {
73
+ return undefined;
74
+ }
75
+
76
+ if (conditions.length === 1) {
77
+ return conditions[0];
78
+ }
79
+
80
+ return { and: conditions };
81
+ }
82
+
83
+ /**
84
+ * Internal hook created by factory
85
+ */
86
+ const useReservationsInternal = createDataHook<
87
+ Reservation,
88
+ UseReservationsOptions,
89
+ { confirmedReservations: Reservation[]; activeReservations: Reservation[] }
90
+ >({
91
+ model: "Reservation",
92
+ dataPropertyName: "reservations",
93
+ buildFilter,
94
+ computedProperties: {
95
+ confirmedReservations: (reservations) =>
96
+ reservations.filter((r) => r.status === "confirmed"),
97
+ activeReservations: (reservations) =>
98
+ reservations.filter((r) => r.status === "confirmed" || r.status === "checked_in"),
99
+ },
100
+ });
101
+
102
+ /**
103
+ * Composable for fetching and managing reservations
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * import { useReservations } from '@htlkg/data/hooks';
108
+ *
109
+ * const { reservations, loading, error, refetch } = useReservations({
110
+ * brandId: 'brand-123',
111
+ * startDate: '2026-01-01',
112
+ * endDate: '2026-01-31',
113
+ * status: 'confirmed'
114
+ * });
115
+ * ```
116
+ *
117
+ * @example With contact filter
118
+ * ```typescript
119
+ * const { reservations, loading } = useReservations({
120
+ * contactId: 'contact-123',
121
+ * limit: 50
122
+ * });
123
+ * ```
124
+ *
125
+ * @example With computed properties
126
+ * ```typescript
127
+ * const { reservations, activeReservations, confirmedReservations } = useReservations({
128
+ * brandId: 'brand-123'
129
+ * });
130
+ *
131
+ * // activeReservations includes confirmed + checked_in
132
+ * // confirmedReservations includes only confirmed
133
+ * ```
134
+ */
135
+ export function useReservations(options: UseReservationsOptions = {}): UseReservationsReturn {
136
+ const result = useReservationsInternal(options);
137
+ return {
138
+ reservations: result.reservations as Ref<Reservation[]>,
139
+ confirmedReservations: result.confirmedReservations as ComputedRef<Reservation[]>,
140
+ activeReservations: result.activeReservations as ComputedRef<Reservation[]>,
141
+ loading: result.loading,
142
+ error: result.error,
143
+ refetch: result.refetch,
144
+ };
145
+ }
@@ -9,26 +9,29 @@ import {
9
9
  checkRestoreEligibility,
10
10
  DEFAULT_SOFT_DELETE_RETENTION_DAYS,
11
11
  } from "../queries/systemSettings";
12
+ import type { CreateAuditFields, UpdateWithSoftDeleteFields } from "./common";
12
13
 
13
14
  /**
14
15
  * Input type for creating an account
15
16
  */
16
- export interface CreateAccountInput {
17
+ export interface CreateAccountInput extends CreateAuditFields {
17
18
  name: string;
18
19
  logo?: string;
19
20
  subscription?: Record<string, any>;
20
21
  settings?: Record<string, any>;
22
+ status?: "active" | "inactive" | "deleted";
21
23
  }
22
24
 
23
25
  /**
24
26
  * Input type for updating an account
25
27
  */
26
- export interface UpdateAccountInput {
28
+ export interface UpdateAccountInput extends UpdateWithSoftDeleteFields {
27
29
  id: string;
28
30
  name?: string;
29
31
  logo?: string;
30
32
  subscription?: Record<string, any>;
31
33
  settings?: Record<string, any>;
34
+ status?: "active" | "inactive" | "deleted";
32
35
  }
33
36
 
34
37
  /**
@@ -9,28 +9,29 @@ import {
9
9
  checkRestoreEligibility,
10
10
  DEFAULT_SOFT_DELETE_RETENTION_DAYS,
11
11
  } from "../queries/systemSettings";
12
+ import type { CreateAuditFields, UpdateWithSoftDeleteFields } from "./common";
12
13
 
13
14
  /**
14
15
  * Input type for creating a brand
15
16
  */
16
- export interface CreateBrandInput {
17
+ export interface CreateBrandInput extends CreateAuditFields {
17
18
  accountId: string;
18
19
  name: string;
19
20
  logo?: string;
20
21
  timezone?: string;
21
- status?: "active" | "inactive" | "maintenance" | "suspended";
22
+ status?: "active" | "inactive" | "maintenance" | "suspended" | "deleted";
22
23
  settings?: Record<string, any>;
23
24
  }
24
25
 
25
26
  /**
26
27
  * Input type for updating a brand
27
28
  */
28
- export interface UpdateBrandInput {
29
+ export interface UpdateBrandInput extends UpdateWithSoftDeleteFields {
29
30
  id: string;
30
31
  name?: string;
31
32
  logo?: string;
32
33
  timezone?: string;
33
- status?: "active" | "inactive" | "maintenance" | "suspended";
34
+ status?: "active" | "inactive" | "maintenance" | "suspended" | "deleted";
34
35
  settings?: Record<string, any>;
35
36
  }
36
37
 
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Common Mutation Input Base Types
3
+ *
4
+ * Provides reusable base interfaces for audit fields to avoid duplication
5
+ * across all mutation input types.
6
+ */
7
+
8
+ /**
9
+ * Audit fields for creation operations
10
+ * Includes timestamps and user tracking
11
+ */
12
+ export interface CreateAuditFields {
13
+ createdAt?: string;
14
+ createdBy?: string;
15
+ updatedAt?: string;
16
+ updatedBy?: string;
17
+ }
18
+
19
+ /**
20
+ * Audit fields for update operations
21
+ * Includes timestamps and user tracking
22
+ */
23
+ export interface UpdateAuditFields {
24
+ updatedAt?: string;
25
+ updatedBy?: string;
26
+ }
27
+
28
+ /**
29
+ * Soft delete fields for entities that support soft deletion
30
+ * Tracks when and by whom an entity was deleted
31
+ */
32
+ export interface SoftDeleteFields {
33
+ deletedAt?: string | null;
34
+ deletedBy?: string | null;
35
+ }
36
+
37
+ /**
38
+ * Complete audit trail for entities with soft delete support
39
+ * Combines update and soft delete fields
40
+ */
41
+ export interface UpdateWithSoftDeleteFields extends UpdateAuditFields, SoftDeleteFields {}
@@ -4,6 +4,14 @@
4
4
  * Provides mutation functions for creating, updating, and deleting data via the GraphQL API.
5
5
  */
6
6
 
7
+ // Common base types
8
+ export type {
9
+ CreateAuditFields,
10
+ UpdateAuditFields,
11
+ SoftDeleteFields,
12
+ UpdateWithSoftDeleteFields,
13
+ } from "./common";
14
+
7
15
  // Brand mutations
8
16
  export {
9
17
  createBrand,
@@ -53,3 +61,17 @@ export {
53
61
  initializeSystemSettings,
54
62
  type UpdateSystemSettingsInput,
55
63
  } from "./systemSettings";
64
+
65
+ // Reservation mutations
66
+ export {
67
+ createReservation,
68
+ updateReservation,
69
+ deleteReservation,
70
+ softDeleteReservation,
71
+ restoreReservation,
72
+ updateReservationStatus,
73
+ ReservationValidationError,
74
+ type CreateReservationInput,
75
+ type UpdateReservationInput,
76
+ type ReservationStatus,
77
+ } from "./reservations";
@@ -132,7 +132,7 @@ describe('ProductInstance Mutations', () => {
132
132
  accountId: 'account-789',
133
133
  enabled: true,
134
134
  version: '1.0.0',
135
- lastUpdated: mockTimestamp,
135
+ updatedAt: mockTimestamp,
136
136
  updatedBy: mockUserId,
137
137
  })
138
138
  );
@@ -183,7 +183,7 @@ describe('ProductInstance Mutations', () => {
183
183
  await createProductInstance(mockClient, validInput);
184
184
 
185
185
  const callArgs = mockCreate.mock.calls[0][0];
186
- expect(callArgs.lastUpdated).toBe(mockTimestamp);
186
+ expect(callArgs.updatedAt).toBe(mockTimestamp);
187
187
  });
188
188
 
189
189
  it('should use provided updatedBy if specified', async () => {
@@ -358,7 +358,7 @@ describe('ProductInstance Mutations', () => {
358
358
  await updateProductInstance(mockClient, validInput);
359
359
 
360
360
  const callArgs = mockUpdate.mock.calls[0][0];
361
- expect(callArgs.lastUpdated).toBe(mockTimestamp);
361
+ expect(callArgs.updatedAt).toBe(mockTimestamp);
362
362
  expect(callArgs.updatedBy).toBe(mockUserId);
363
363
  });
364
364
 
@@ -9,6 +9,7 @@ import type { ProductInstance } from "@htlkg/core/types";
9
9
  import { getClientUser } from "@htlkg/core/auth";
10
10
  import { getCurrentTimestamp } from "@htlkg/core/utils";
11
11
  import { AppError } from "@htlkg/core/errors";
12
+ import type { CreateAuditFields, UpdateAuditFields } from "../common";
12
13
 
13
14
  /**
14
15
  * Get current user identifier for audit trails
@@ -29,7 +30,7 @@ async function getUserIdentifier(fallback = "system"): Promise<string> {
29
30
  /**
30
31
  * Input type for creating a product instance
31
32
  */
32
- export interface CreateProductInstanceInput {
33
+ export interface CreateProductInstanceInput extends CreateAuditFields {
33
34
  productId: string;
34
35
  brandId: string;
35
36
  accountId: string;
@@ -37,21 +38,16 @@ export interface CreateProductInstanceInput {
37
38
  enabled: boolean;
38
39
  config?: Record<string, any>;
39
40
  version?: string;
40
- createdBy?: string;
41
- lastUpdated?: string;
42
- updatedBy?: string;
43
41
  }
44
42
 
45
43
  /**
46
44
  * Input type for updating a product instance
47
45
  */
48
- export interface UpdateProductInstanceInput {
46
+ export interface UpdateProductInstanceInput extends UpdateAuditFields {
49
47
  id: string;
50
48
  enabled?: boolean;
51
49
  config?: Record<string, any>;
52
50
  version?: string;
53
- lastUpdated?: string;
54
- updatedBy?: string;
55
51
  }
56
52
 
57
53
  /**
@@ -81,6 +77,7 @@ export async function createProductInstance<TClient = any>(
81
77
  const userIdentifier = input.createdBy || input.updatedBy || await getUserIdentifier();
82
78
 
83
79
  // Build input - manually construct to avoid Vue Proxy issues
80
+ const timestamp = input.createdAt || getCurrentTimestamp();
84
81
  const createInput: any = {
85
82
  productId: input.productId,
86
83
  productName: input.productName,
@@ -88,8 +85,9 @@ export async function createProductInstance<TClient = any>(
88
85
  accountId: input.accountId,
89
86
  enabled: input.enabled,
90
87
  version: input.version,
88
+ createdAt: timestamp,
91
89
  createdBy: userIdentifier,
92
- lastUpdated: input.lastUpdated || getCurrentTimestamp(),
90
+ updatedAt: input.updatedAt || timestamp,
93
91
  updatedBy: userIdentifier,
94
92
  };
95
93
 
@@ -154,7 +152,7 @@ export async function updateProductInstance<TClient = any>(
154
152
  // Convert config from Vue Proxy to plain object
155
153
  const updateInput: any = {
156
154
  ...input,
157
- lastUpdated: input.lastUpdated || getCurrentTimestamp(),
155
+ updatedAt: input.updatedAt || getCurrentTimestamp(),
158
156
  updatedBy: input.updatedBy || await getUserIdentifier(),
159
157
  };
160
158